Go Web轻量级框架Gin学习系列:数据绑定

栏目: Go · 发布时间: 5年前

内容简介:前面写了两篇与下面是

前面写了两篇与 Gin 框架学习有关的文章,主要讲了 Gin 框架的安装,定义处理 HTTP 请求的各种方法以及如何根据客户端需求返回不同格式的数据,但这中间漏了一个环节,那就是返回数据之前,如何获取客户端 HTTP 请求中带上来的参数,关于这点,我们就在这篇文章中讲一讲。

Gin 框架将处理 HTTP 请求参数以及如何响应等操作都封装到了 gin.Conetxt 结构体,并为 gin.Context 提供了非常多的方法,因此了解 gin.Context 的结构定义与方法,对使用 Gin 框架编写 Web 项目非常重要。

下面是 gin.Context 结构定义代码:

type Context struct {
    Request *http.Request
    Writer  ResponseWriter
    Params Params
    // Keys is a key/value pair exclusively for the context of each request.
    Keys map[string]interface{}
    // Errors is a list of errors attached to all the handlers/middlewares who used this context.
    Errors errorMsgs
    // Accepted defines a list of manually accepted formats for content negotiation.
    Accepted []string
    // contains filtered or unexported fields
}
复制代码

从上面的 gin.Context 的结构定义来看, gin.Context 封装了 http.Requesthttp.ResponseWriter

获取请求参数

1. Path

path是指请求的url中域名之后从/开始的部分,如掘金首页地址: https://juejin.im/timeline/timeline 部分便是path,可以使用gin.Context中的Param()方法获取这部分参数。

func (c *Context) Param(key string) string
复制代码

使用Param()方法获取path中的参数:

r.GET("/user/:id",func(c *gin.Context){
    id := c.Param("id")
})
复制代码

除了使用gin.Context的中Param()方法外,还可以用gin.Context中的Params字段获取到path中的参数,Params的定义如下:

type Params []Param
func (ps Params) ByName(name string) (va string)
func (ps Params) Get(name string) (string, bool)
复制代码

使用gin.Context中的Params字段获取path中的参数示例如下:

r.GET("/user/:id",func(c *gin.Context){
    id,err := c.Params.Get("id")
    //id := c.Params.ByName("id")
})
复制代码

2. Query

query是指url请求地址中的问号后面的部,称为查询参数,如下面地址中, query=%E6%96%87%E7%AB%A0&type=all 就是查询参数。

https://juejin.im/search?query=%E6%96%87%E7%AB%A0&type=all
复制代码

gin.Context 提供了以下几个方法,用于获取Query部分的参数。

1. 获取单个参数

func (c *Context) GetQuery(key string) (string, bool)
func (c *Context) Query(key string) string
func (c *Context) DefaultQuery(key, defaultValue string) string
复制代码

上面三个方法用于获取单个数值, GetQueryQuery 多返回一个error类型的参数,实际上 Query 方法只是封装了 GetQuery 方法,并忽略 GetQuery 方法返回的错误而已,而DefaultQuery方法则在没有获取相应参数值的返回一个默认值。

示例如下:

r.GET("/user", func(c *gin.Context) {
    id,_ := c.GetQuery("id")
    //id := c.Query("id")
    //id := c.DefaultQuery("id","10")
    c.JSON(200,id)
})
复制代码

请求: http://localhost:8080/user?id=11

响应: 11

2. 获取数组

GetQueryArray方法和QueryArray的区别与GetQuery和Query的相似。

func (c *Context) GetQueryArray(key string) ([]string, bool)
func (c *Context) QueryArray(key string) []string

复制代码

示例如下:

r.GET("/user", func(c *gin.Context) {
    ids := c.QueryArray("id")
    //id,_ := c.QueryArray("id")
    c.JSON(200,ids)
})
复制代码

请求: http://localhost:8080/user?id=10&id=11&id=12

响应: ["10","11","12"]

3. 获取map

GetQueryArray方法和QueryArray的区别与GetQuery和Query的相似。

func (c *Context) QueryMap(key string) map[string]string
func (c *Context) GetQueryMap(key string) (map[string]string, bool)
复制代码

示例如下:

r.GET("/user", func(c *gin.Context) {
    ids := c.QueryMap("ids")
    //ids,_ := c.GetQueryMap("ids")
    c.JSON(200,ids)
})
复制代码

请求: http://localhost:8080/user?ids[10]=zhang

响应: {"10":"zhang"}

3. Body

一般HTTP的Post请求参数都是通过body部分传给服务器端的,尤其是数据量大或安全性要求较高的数据,如登录功能中的账号密码等参数。

gin.Context提供了以下四个方法让我们获取body中的数据,不过要说明的是,下面的四个方法,只能获取 Content-typeapplication/x-www-form-urlencodedmultipart/form-databody 中的数据。

下面方法的使用方式与上面获取Query的方法使用类型,区别只是数据来源不同而已,这里便不再写示例程序。

func (c *Context) PostForm(key string) string
func (c *Context) PostFormArray(key string) []string
func (c *Context) PostFormMap(key string) map[string]string
func (c *Context) DefaultPostForm(key, defaultValue string) string
func (c *Context) GetPostForm(key string) (string, bool)
func (c *Context) GetPostFormArray(key string) ([]string, bool)
func (c *Context) GetPostFormMap(key string) (map[string]string, bool)
func (c *Context) GetRawData() ([]byte, error)
复制代码

数据绑定

在前面的例子中,我们直接使用 gin.Context 提供的方法获取请求中通过 pathquerybody 带上来的参数,但使用前面的那些方法,并不能处理请求中比较复杂的数据结构,比如Content-type为application/json或application/xml时,其所带上的数据会很复杂,因此我们需要使用另外一种方法获取这些数据,这种方式叫 数据绑定

Gin 框架将数据绑定的操作都封装在gin/binding这个包中,下面是 gin/binding包 定义的常量,说明 gin/binding 包所支持的 Content-type 格式。

const (
    MIMEJSON              = "application/json"
    MIMEHTML              = "text/html"
    MIMEXML               = "application/xml"
    MIMEXML2              = "text/xml"
    MIMEPlain             = "text/plain"
    MIMEPOSTForm          = "application/x-www-form-urlencoded"
    MIMEMultipartPOSTForm = "multipart/form-data"
    MIMEPROTOBUF          = "application/x-protobuf"
    MIMEMSGPACK           = "application/x-msgpack"
    MIMEMSGPACK2          = "application/msgpack"
    MIMEYAML              = "application/x-yaml"
)
复制代码

gin.binding 包也定义处理不同 Content-type 提交数据的处理结构体,并以变量的形式让其他包可以访问,如下:

var (
    JSON          = jsonBinding{}
    XML           = xmlBinding{}
    Form          = formBinding{}
    Query         = queryBinding{}
    FormPost      = formPostBinding{}
    FormMultipart = formMultipartBinding{}
    ProtoBuf      = protobufBinding{}
    MsgPack       = msgpackBinding{}
    YAML          = yamlBinding{}
    Uri           = uriBinding{}
)
复制代码

但实际上,我们并不需要调用 gin/binding 包的代码来完成数据绑定的功能,因为 gin.Context 中已经在 gin.Context 的基础上封装了许多更加快捷的方法供我们使用:

gin.Context 封装的相关绑定方法,分为以 Bind 为前缀的系列方法和以 ShouldBind 为前缀的系列方法,这两个系列方法之间的差别在于以Bind为前缀的方法,在用户输入数据不符合相应格式时,会直接返回http状态为400的响应给客户端。

以Bind为前缀的系列方法

1. Path

func (c *Context) BindUri(obj interface{}) error
复制代码

代码示例:

type User struct {
    Uid      int    //用户id
    Username string //用户名
}
func main() {
    r := gin.Default()
    r.GET("/bind/:uid/username", func(c *gin.Context) {
        var u User
        e := c.BindUri(&u)
        if e == nil{
            c.JSON(200,u)
        }
    })
    r.Run()
}

复制代码

请求: http://localhost:8080/bind/1/小张

输入: {1,"小张"}

2. Query

func (c *Context) BindQuery(obj interface{}) error
复制代码

代码示例:

r.GET("/bind/:uid/username", func(c *gin.Context) {
    var u User
    e := c.BindQuery(&u)
    if e == nil{
        c.JSON(200,u)
    }
})
复制代码

请求: http://localhost:8080/bind?uid=1&username=小张

输出: {1,"小张"}

3. Body

当我们在 HTTP 请求中 Body 设置不同数据格式,需要设置相应头部 Content-Type 的值,比较常用为 jsonxmlyamlgin.Context 提供下面三个方法绑定对应Content-type时body中的数据。

func (c *Context) BindJSON(obj interface{}) error
func (c *Context) BindXML(obj interface{}) error
func (c *Context) BindYAML(obj interface{}) error
复制代码

除了上面三个方法外,更常用的Bind()方法,Bind()方法会自动根据Content-Type的值选择不同的绑定类型。

func (c *Context) Bind(obj interface{}) error
复制代码

示例

r.POST("bind",func(c *gin.Context){
    u := User{}
    c.Bind(&u)
})
复制代码

上面几个方法都是获取固定Content-type或自动根据Content-type选择绑定类型,我们也可以使用下面两个方法自行选择绑定类型。

下面两个方法的第二个参数值是gin.binding中定义好的常量,我们在上面讲过。

func (c *Context) BindWith(obj interface{}, b binding.Binding) error
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error
复制代码

示例

r.POST("bind",func(c *gin.Context){
	u := User{}
	c.BindWith(&u,binding.JSON)
    c.MustBindWith(&u,binding.JSON)
})
复制代码

以ShouldBind为前缀的系列方法

以ShouldBind为前缀的相应的方法与以Bind为前缀的方法使用基本相同,因此下面没有相应演示的代码。

1. Path

func (c *Context) ShouldBindUri(obj interface{}) error
复制代码

2. Query

func (c *Context) ShouldBindQuery(obj interface{}) error
复制代码

3. Body

func (c *Context) ShouldBind(obj interface{}) error
func (c *Context) ShouldBindJSON(obj interface{}) error
func (c *Context) ShouldBindXML(obj interface{}) error
func (c *Context) ShouldBindYAML(obj interface{}) error
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error)
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error
复制代码

小结

Gin 框架在 net/http 包的基础上封装了许多的方法,让我们可以接收客户端传递上来的各种不同格式的数据,但是从客户端得到的数据之后,还是要验证数据是否合法或是否我们想要的,这是 Gin 框架中有关 数据验证器 的知识了,有机会再写写这方面的文章。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Big C++中文版

Big C++中文版

霍斯特曼 / 姚爱红 / 电子工业 / 2007-3 / 85.00元

本书是一本关于C++的优秀教材,南圣何塞州立大学知名教授Horstmann编写。全书深入探讨了C++的知识,并着重强调了安全的标准模板库;本书较厚,但它可用做程序设计专业学生的教材(两学期)。全书在介绍基础知识后,作者论及了一些高级主题。书中面向对象的设计一章探讨了软件开发生命周期问题,给出了实现类关联的实用提示。其他高级主题包括模板,C++标准模板库,设计模式,GUI,关系数据库以及XML等。本......一起来看看 《Big C++中文版》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试