公众号:程序员读书,欢迎关注
在添加路由处理函数之后,就可以在路由处理函数中编写业务处理代码了,而编写业务代码第一件事一般就是获取HTTP
请求的参数吧。
传递参数的方式
在一个HTTP
请求中,一般可以把上传参数分为以下三个部分:
Header
Header
是HTTP
请求中一个键值对集合,HTTP
规范定义了很多的Headeer
,比如Content-Type
,Accept
等,不过也可以自定义请求头部或者响应头部。
URL
URL
指的是请求路径,在请求路径上可以通过两种方式携带请求参数,一种是直接写在请求路径上的,称为URL Path
:
bash
http://localhost:8080/user/add/1
上面的参数1
就是URL Path
。
在URL
上传递参数的另外一种方式就是URL Query
,URL Query
参数是指跟在?
后面的键值对集合,多个参数之间以&
分隔的:
bash
http://localhost:8080/user/add/1?name=小明&gender=男
HTTP Body
HTTP Body
参数是指HTTP请求的请求体所携带的参数,这部分参数会因为Content-Type
不同而不同,比如当Content-Type
为application/json
时,HTTO Body
携带的是一串JSON
字符串。
那么,在Gin
框架中,要如何获取这些请求参数呢?主要有以下两种方式:
- 直接用
Gin
封装的方法获取请求参数 - 通过绑定的方式来获取请求参数
直接获取请求参数
Gin
框架在net/http
包的基础上封装了获取参数的方式。
获取URL Path中的参数
在路由中使用通配符时,对应的通配符就会成为URL Path
参数,调用gin.Context
的Param()
方法可以获取Path
参数:
css
package main
func main(){
engine := gin.Default()
engine.GET("/user/:id", func(ctx *gin.Context) {
id := ctx.Param("id")
fmt.Fprintf(ctx.Writer, "你的请求id:%s", id)
})
engine.Run()
}
运行后发起请求:
bash
$ curl http://localhost:8080/user/100
你的请求id:100
获取URL Query中的参数
gin.Context
对象提供了以下几个主要方法用于获取Query
参数:
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.New()
engine.GET("/user/list", func(ctx *gin.Context) {
//获取单个值
name := ctx.Query("name")
//带默认值
gender := ctx.DefaultQuery("gender", "男")
//数组
habits := ctx.QueryArray("habits")
//map
works := ctx.QueryMap("works")
fmt.Printf("%s,%s,%s,%s\n", name, gender, habits, works)
})
engine.Run()
}
运行后发起请求:
css
curl --location --globoff --request GET 'http://localhost:8080/user/list?name=test&gender=%E5%A5%B3&habits=%E7%9C%8B%E4%B9%A6&habits=%E7%9C%8B%E7%94%B5%E5%BD%B1&works[%E5%86%99ppt]=1&works[%E5%86%99%E4%BB%A3%E7%A0%81]=1' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=test' \
--data-urlencode 'email=test@163.com'
获取HTTP Body中的参数
对于通过HTTP Body
传上来的参数,gin.Context
也提供了几种主要方法用于获取:
go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.New()
engine.POST("/user/add", func(ctx *gin.Context) {
//获取单个值
name := ctx.PostForm("name")
//带默认值
gender := ctx.DefaultPostForm("gender", "男")
//数组
habits := ctx.PostFormArray("habits")
//map
works := ctx.PostFormMap("works")
fmt.Printf("%s,%s,%s,%s\n", name, gender, habits, works)
})
engine.Run()
}
绑定请求参数
Gin
支持绑定Header
,URL Path
,URL Query
以及HTTP Body
等不同位置数据。
绑定Header参数
绑定Header
参数可以使用BindHeader()
或者ShouldBindHeader()
方法:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type testHeader struct {
Rate int `header:"Rate"`
Domain string `header:"Domain"`
}
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
h := testHeader{}
if err := c.ShouldBindHeader(&h); err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
fmt.Printf("%#v\n", h)
c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain})
})
r.Run()
}
运行后的请求结果:
ruby
$ curl -H "rate:300" -H "domain:music" http://localhost:8080/
{"Domain":"music","Rate":300}
绑定URL Path参数
绑定URL Path
参数可以使用BindUri()
或者ShouldBindUri()
方法:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `uri:"name"`
Email string `uri:"email"`
}
func main() {
engine := gin.New()
engine.GET("/user/list/:id/:name", func(ctx *gin.Context) {
var u User
if err := ctx.BindUri(&u);err != nil {
ctx.JSON(http.StatusBadRequest, err)
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
绑定URL Query参数
绑定URL Query
参数可以使用BindQuery()
、ShouldBindQury()
、Bind()
或者ShouldBind()
方法:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `form:"name"`
Email string `form:"email"`
}
func main() {
engine := gin.New()
engine.GET("/user/list", func(ctx *gin.Context) {
var u User
if err := ctx.BindQuery(&u);err != nil {
ctx.JSON(http.StatusBadRequest, err)
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
绑定HTTP Body参数
我们知道HTTP Body
的参数会根据不同Content-Type
传不同格式的数据,Gin
支持以下几种Content-Type
类型的绑定:
- JSON
- XML
- TOML
- YAML
- x-www-form-urlencoded
- multipart/form-data
注意HTTP Body
的数据只在POST
请求时才会进行绑定。
绑定HTTP Body
参数可以用Bind()
和ShouldBind()
方法,这两个方法会根据当前请求的Content-Type
类型自动判断请求的类型。
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string
Email string
}
func main() {
engine := gin.New()
engine.POST("/user/add", func(ctx *gin.Context) {
var u User
if err := ctx.Bind(&u); err != nil {
ctx.JSON(http.StatusBadRequest, err.Error())
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
如果明确请求数据的类型,也可以直接调用对应类型绑定的方法,比如确定是JSON
格式数据的话,可以调用BindJSON()
或者ShouldBindJSON()
:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string
Email string
}
func main() {
engine := gin.New()
engine.POST("/user/add", func(ctx *gin.Context) {
var u User
if err := ctx.BindJSON(&u); err != nil {
ctx.JSON(http.StatusBadRequest, err.Error())
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
对于x-www-form-urlencoded
和multipart/form-data
,与Qurey
参数一样,结构体需要添加form
的tag
:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `form:"name"`
Email string `form:"email"`
}
func main() {
engine := gin.New()
engine.POST("/user/add", func(ctx *gin.Context) {
var u User
if err := ctx.Bind(&u); err != nil {
ctx.JSON(http.StatusBadRequest, err.Error())
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
数据校验
在数据绑定的时候,也可以进行数据校验:
go
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
type User struct {
Name string `binding:"required"`
Email string `binding:"required,email"`
}
func main() {
engine := gin.New()
engine.POST("/user/add", func(ctx *gin.Context) {
var u User
if err := ctx.Bind(&u); err != nil {
ctx.JSON(http.StatusBadRequest, err.Error())
return
}
fmt.Fprintf(ctx.Writer, "你输入的用户名为:%s,邮箱为:%s\n", u.Name, u.Email)
})
engine.Run()
}
运行后发起请求的结果:
css
$ curl --location 'http://localhost:8080/user/add' \
--header 'Content-Type: application/json' \
--data-raw '{
"id":10,
"name":"test",
"email":"test@163.com"
}'
你输入的用户名为:test,邮箱为:test@163.com
两种方式的对比
相较于直接获取请求参数,请求数据绑定是一种更强大且优雅的参数获取方式,使用这种方式获取参数有以下几个好处:
- 直接将所有参数绑定到一个结构体中,不需要手动一个个地获取参数。
- 绑定后的参数会自动转换为结构体对应字段的类型,不需要手动对每个参数进行数据类型转换。
- 在进行数据绑定的同时还可以进行数据校验。
小结
直接获取请求参数虽然没有绑定参数那么强大,但对于简单的请求来说,也是够用的,因此,我们可以根据自己的需求,选择对应的方式来获取请求参数。