Gin框架---参数获取和绑定

标签:Go语言首次发布:2023-11-13最近修改:2024-04-02

获取 Query 参数

Query 参数又叫 Querystring 参数,是 URL 的?后面的一串字符串。

Demo 代码如下:

go
r.GET("/home", func(c *gin.Context) {    username := c.Query("username")    password := c.DefaultQuery("password", "******")    addr := c.QueryArray("addr")    class := c.QueryMap("class")    age, ok := c.GetQuery("age")    if ok = true {        fmt.Println(ok)    }    c.JSON(http.StatusOK, gin.H{        "username": username,        "password": password,        "addr":     addr,        "class":    class,        "age":      age,    })})

结果如下:

image-20230328201715768 image-20230328201949671

总结:

  1. Query()用来获取参数

  2. 使用 DefaultQuery()方法时,如果没有相应的参数,就会使用 defaultValue 的值来代替。

  3. QueryArray()和 QueryMap()方法分别获取切片类型和字典类型的参数

  4. GetQuery()方法返回两个值,一个 value,一个 bool 值。当能够获取到相应的值时,bool 值=true;当不能够获取到相应的值时,value 为空,bool 值=false。

  5. 需要注意的是切片类型的参数和字典类型的参数的写法。

    • 切片:addr=aaa&addr=bbb
    • 字典:class[专业]=软件工程&class[年级]=大一

获取 Path 参数

Path 参数就是路径参数,也就是 URL 中斜杠和斜杠之间的参数

Demo 代码如下:

go
r.GET("/user/info/:username/:password/:hobby", func(c *gin.Context) {    username := c.Param("username")    password := c.Param("password")    hobby := c.Param("hobby")    params := c.Params        c.JSON(http.StatusOK, gin.H{        "username": username,        "password": password,        "hobby":    hobby,        "params":   params,    })})

结果如下:

image-20230328205658430

总结:

  1. 把获取的 Path 参数的前面加上“ : ”,就表示这个 Path 参数是要获取的参数。

  2. Param()方法只能一个一个的获取参数。

  3. Params()方法是一次性获取所有的 Path 参数,返回的是 Params 类型,该类型的定义如下

    go
    type Param struct {    Key   string    Value string}type Params []Param
  4. 当有一部分 Path 参数获取不到时,前面获取到的 Path 参数都会全部丢弃。其本质原因是底层使用 rang 遍历所有的 Path 参数,如果没有相应的参数,会把整个 params 切片置为空。源码如下:

    go
    func (ps Params) Get(name string) (string, bool) {    for _, entry := range ps {        if entry.Key == name {            return entry.Value, true        }    }    return "", false //注意:并不是将entry.Value置为nil,而是将整个切片置为空。}func (ps Params) ByName(name string) (va string) {    va, _ = ps.Get(name)    return}func (c *Context) Param(key string) string {    return c.Params.ByName(key)}

获取 Form 表单参数

Demo 代码如下:

go
r.POST("/info", func(c *gin.Context) {    username := c.PostForm("username")    password := c.DefaultPostForm("password", "******")    hobby := c.PostFormArray("hobby")    sex, ok := c.GetPostForm("sex")    if ok != true {      fmt.Println(ok)    }        c.JSON(http.StatusOK, gin.H{        "username": username,        "password": password,        "sex":      sex,        "hobby":    hobby,    })})

结果如下:

image-20230329140639480 image-20230329140320814

总结:

  1. PostForm()方法获取表单参数
  2. 使用 DefaultPostForm()方法如果没有获取到参数,会有默认值代替
  3. PostFormArray()获取数组对象的表单参数
  4. GetPostForm()方法返回两个值,第一个是表单参数,第二个是 bool 值

获取 Json 参数

Demo 代码如下:

go
r.POST("/json", func(c *gin.Context) {    var m map[string]interface{}    body, err := c.GetRawData() //从请求体(body)中获取json数据    if err = nil {        fmt.Println(err.Error())    }    err = json.Unmarshal(body, &m)    if err = nil {        fmt.Println(err.Error())    }    name := m["name"]    email := m["email"]    c.JSON(http.StatusOK, gin.H{        "name":  name,        "email": email,    })})

结果如下:

image-20230329163925637

总结:

  1. GetRawData()方法是从请求体(body)中获取原始的 json 数据

  2. GetRawData()底层使用 ioutil 包里面的 ReadAll()方法来读取数据,ReadAll()方法底层使用 io 包里面的 ReadAll()函数,ReadAll()函数的源码如下:

    go
    func ReadAll(r Reader) ([]byte, error) {    b := make([]byte, 0, 512)    for {        if len(b) == cap(b) {            // Add more capacity (let append pick how much).            b = append(b, 0)[:len(b)]        }        n, err := r.Read(b[len(b):cap(b)])        b = b[:len(b)+n]        if err = nil {            if err == EOF {                err = nil            }            return b, err        }    }}

    源码分析可以看这篇文章:

    io.ReadAll 怎样读全部

获取请求头中的数据

Demo 代码如下:

go
r.GET("/header", func(c *gin.Context) {    token := c.GetHeader("Authorization")    c.JSON(http.StatusOK, gin.H{        "Authorization": token,    })})

结果如下:

image-20230329165517194
  1. GetHeader()方法用于获取请求头信息
  2. 设置请求头的方法有两种:
    • c.Header(“Authorization”, “xxx.yyy.zzz”)
    • c.Writer.Header().Set(“Authorization”, “xxx.yyy.zzz”)

数据绑定

基于请求的 Content-Type 识别请求数据类型并利用反射机制自动提取请求中 QueryString、form 表单、JSON、XML 等参数到结构体中。 下面的示例代码演示了 BindJSON()和 ShouldBindJSON,它能够基于请求自动提取 JSON 类型的数据,并把值绑定到指定的结构体对象。

Demo 代码如下:

go
type Login struct {    Username string `json:"username"`    Password string `json:"password"`}r.GET("/bindJson", func(c *gin.Context) {    var login Login    err := c.BindJSON(&login)    if err != nil {        fmt.Println(err.Error())    }    username := login.Username    password := login.Password    c.JSON(http.StatusOK, Login{        Username: username,        Password: password,    },    )})r.GET("/shouldBindJson", func(c *gin.Context) {    var login Login    err := c.ShouldBindJSON(&login)    if err != nil {        fmt.Println(err.Error())    }    username := login.Username    password := login.Password    c.JSON(http.StatusOK, Login{        Username: username,        Password: password,    },    )})

结果如下:

总结:

  1. 数据绑定是利用结构体的反射机制来实现的,只要结构体里面有相应的 Tag 标签,就能实现对应数据类型的绑定。
  2. ShouldBindxxx 和 Bindxxx 区别:如果 Bindxxx 没有绑定到数据,会在 Header 中添加 400 的返回信息,而 ShouldBindxxx 不会。验证结果如下: