获取 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, })})结果如下:
bash
$ curl -X GET "http://127.0.0.1:8080/home?username=bing&password=123456&addr=aaa&addr=bbb&class[专业]=软件工程&class[年级]=大一&age=20"{ "addr": [ "aaa", "bbb" ], "age": "20", "class": { "专业": "软件工程", "年级": "大一" }, "password": "123456", "username": "bing"}$ curl -X GET "http://127.0.0.1:8080/home?username=bing"{ "addr": null, "age": "", "class": {}, "password": "******", "username": "bing"}总结
- Query()用来获取参数
- 使用 DefaultQuery()方法时,如果没有相应的参数,就会使用 defaultValue 的值来代替。
- QueryArray()和 QueryMap()方法分别获取切片类型和字典类型的参数
- GetQuery()方法返回两个值,一个 value,一个 bool 值。当能够获取到相应的值时,bool 值=true;当不能够获取到相应的值时,value 为空,bool 值=false。
- 需要注意的是切片类型的参数和字典类型的参数的写法。
- 切片: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, })})结果如下:
bash
$ curl -X GET "http://127.0.0.1:8080/user/info/bing/123456/ 双色球"{ "hobby": "双色球", "params": [ { "Key": "username", "Value": "bing" }, { "Key": "password", "Value": "123456" }, { "Key": "hobby", "Value": "双色球" } ], "password": "123456", "username": "bing"}总结
- 把获取的 Path 参数的前面加上
:符号,就表示这个 Path 参数是要获取的参数。 - Param()方法只能一个一个的获取参数。
- Params()方法是一次性获取所有的 Path 参数,返回的是 Params 类型,该类型的定义如下go
type Param struct { Key string Value string}type Params []Param - 当有一部分 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, })})结果如下:
bash
$ curl -X POST "http://127.0.0.1:8080/info" -F "username=bing"{ "hobby": null, "password": "******", "sex": "", "username": "bing"}$ curl -X POST "http://127.0.0.1:8080/info" \ -F "username=bing" \ -F "password=123456" \ -F "sex=男" \ -F "hobby=篮球" \ -F "hobby=足球" \ -F "hobby=双色球"{ "hobby": [ "篮球", "足球", "双色球" ], "password": "123456", "sex": "男", "username": "bing"}总结
- PostForm()方法获取表单参数
- 使用 DefaultPostForm()方法如果没有获取到参数,会有默认值代替
- PostFormArray()获取数组对象的表单参数
- 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, })})结果如下:
bash
$ curl -X POST "http://127.0.0.1:8080/json" \ -H "Content-Type: application/json" \ -d '{"name":"bing","email":"123456@qq.com"}'{ "email": "123456@qq.com", "name": "bing"}总结
- GetRawData()方法是从请求体(body)中获取原始的 json 数据
- GetRawData()底层使用 ioutil 包里面的 ReadAll()方法来读取数据,ReadAll()方法底层使用 io 包里面的 ReadAll()函数,ReadAll()函数的源码如下:源码分析可以看这篇文章:io.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 } }}
获取请求头中的数据
Demo 代码如下:
go
r.GET("/header", func(c *gin.Context) { token := c.GetHeader("Authorization") c.JSON(http.StatusOK, gin.H{ "Authorization": token, })})结果如下:
bash
$ curl -X GET "http://127.0.0.1:8080/header" -H "Authorization: aaa.bbb.ccc"{ "Authorization": "aaa.bbb.ccc"}总结
- GetHeader()方法用于获取请求头信息
- 设置请求头的方法有两种:
- 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 { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } 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 { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } username := login.Username password := login.Password c.JSON(http.StatusOK, Login{ Username: username, Password: password, })})结果如下:
bash
$ curl -X GET "http://127.0.0.1:8080/bindJson" \ -H "Content-Type: application/json" \ -d '{"username":"bing","password":"123"}'{ "username": "bing", "password": "123"}$ curl -X GET "http://127.0.0.1:8080/shouldBindJson" \ -H "Content-Type: application/json" \ -d '{"username":"bing","password":"123"}'{ "username": "bing", "password": "123"}$ curl -i -X GET "http://127.0.0.1:8080/shouldBindJson"HTTP/1.1 400 Bad Request{ "error": "EOF"}总结
- 数据绑定是利用结构体的反射机制来实现的,只要结构体里面有相应的 Tag 标签,就能实现对应数据类型的绑定。
- ShouldBindxxx 和 Bindxxx 区别:如果 Bindxxx 没有绑定到数据,会在 Header 中添加 400 的返回信息,而 ShouldBindxxx 不会。
Comments