Gin 的请求参数获取
http 的请求参数通常通过以下集中方式传入。
- 附加在 url 后面的(用 ? 分隔)的 query 参数,譬如下面的 name 和 age:
127.0.0.1:8080/query?name=XX&age=11
- URI 中特定位置的字符认做传入参数:
假设路径参数定义为:/user/NAME/ACTION
127.0.0.1:8080/user/xiaoming/run 传入的参数就是 NAME=xiaoming,ACTION=run
-
在 HTTP Header 中设置的参数
-
通过 post 提交的、位于 http 请求 body 中的数据
以上参数以及其它所有的请求信息,都传入的 *gin.Context 获取。
URI query 参数
URL 的多个 query 参数用 & 间隔,用 c.QueryXX 方法读取:
//匹配:127.0.0.1:8080/query?name=xiaoming&age=11
func query(c *gin.Context) {
name := c.DefaultQuery("name", "Guest")
age := c.Query("age")
c.String(http.StatusOK, "%s is %s years\n", name, age)
}
同名的参数被认为是数组:
//匹配:"127.0.0.1:8080/arr?ids=A&ids=B"
func queryArray(c *gin.Context) {
ids := c.QueryArray("ids")
c.JSON(http.StatusOK, gin.H{
"ids": ids,
})
}
Map 参数的传递方法:
//匹配:"127.0.0.1:8080/map?ids[a]=1234&ids[b]=hello"
func queryMap(c *gin.Context) {
ids := c.QueryMap("ids")
c.JSON(http.StatusOK, gin.H{
"ids": ids,
})
}
除了上面的参数读取方法,还可以通过 c.ShouldBindQuery 直接将参数解析到变量中:
type UserInfo struct {
Name string `form:"name"`
Age int `form:"age"`
Message []string `form:"message"`
MoreInfo map[string]string `form:"moreinfo"`
}
func queryBind(c *gin.Context) {
var userInfo UserInfo
c.BindQuery(&userInfo)
//gin 1.5 的 BindQuery 似乎不支持 map,单独获取
userInfo.MoreInfo = c.QueryMap("moreinfo")
c.JSON(http.StatusOK, userInfo)
}
Http Header
用 c.GetHeader() 获取:
func header(c *gin.Context) {
token := c.GetHeader("TOKEN")
c.JSON(http.StatusOK, gin.H{
"TOKEN": token,
})
}
用 c.BindHeader 直接解析到变量中:
type Token struct {
Token string `header:"token"`
}
func headerBind(c *gin.Context) {
var token Token
c.BindHeader(&token)
c.JSON(http.StatusOK, token)
}
URI 路径参数
路径参数需要定义路由时,在路径中进行注明,用 c.Param() 读取:
func userName(c *gin.Context) {
name := c.Param("name")
c.String(http.StatusOK, "Hello %s\n", name)
}
func userNameAction(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
c.String(http.StatusOK, "%s is %s\n", name, action)
}
func main() {
router := gin.Default()
// curl 127.0.0.1:8080/user/xiaoming
// :name 必须存在
// 匹配 /user/NAME
// 不匹配 /user 或者 /user/
router.GET("/user/:name", userName)
// curl 127.0.0.1:8080/user/xiaoming/run
// *action 是可选的
// 匹配 /user/NAME/
// 匹配 /user/NAME/ACTION
// 如果 /user/NAME 没有对应的 router,重定向到 /user/NAME/
router.GET("/user/:name/*action", userNameAction)
// curl -X POST 127.0.0.1:8080/user/xiaoming/run
// POST 也可以使用路径参数
router.POST("/user/:name/*action", userNameAction)
router.Run()
}
用 c.BindUri 直接解析到变量中:
type UserInfo struct {
Name string `uri:"name"`
Action string `uri:"action"`
}
func bindURI(c *gin.Context) {
var userInfo UserInfo
c.BindUri(&userInfo)
c.JSON(http.StatusOK, userInfo)
}
POST:form 表单数据
post 提交的参数位于 http 请求的 body 中,可以是任意字符,这里以 form 表单数据为例。
form 表单参数用 c.PostXX 读取,格式与 URL query 参数相同,也支持数组和 map。
func postForm(c *gin.Context) {
message := c.PostForm("message")
name := c.DefaultPostForm("name", "guest")
c.String(http.StatusOK, "%s %s", name, message)
}
func postFormMap(c *gin.Context) {
ids := c.PostFormMap("ids")
c.JSON(http.StatusOK, gin.H{
"ids": ids,
})
}
func postFormArray(c *gin.Context) {
ids := c.PostFormArray("ids")
c.JSON(http.StatusOK, gin.H{
"ids": ids,
})
}
func main() {
router := gin.Default()
// curl -XPOST 127.0.0.1:8080/form -d "name=xiaoming&message=welcome!"
router.POST("/form", postForm)
// curl -XPOST 127.0.0.1:8080/map -d "ids[first]=100&ids[second]=200"
router.POST("/map", postFormMap)
// curl -XPOST 127.0.0.1:8080/map -d "ids=100&ids=200"
router.POST("/arr", postFormArray)
router.Run()
}
POST:json/xml/yaml
前面例子读取了 form 表单参数,在实际开发中,post 提交的参数还经常是 json、xml 格式。
Gin 内置了 json、xml 数据的解析方法,不需要额外写转换代码。Gin 可以把 form 表单、json、xml 数据直接解析到对应的变量中。
在定义变量的类型时,需要在 struct tag 中指定对应的参数名:
type Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required" `
}
解析 JSON 数据:
func bindXML(c *gin.Context) {
var login Login
if err := c.ShouldBindXML(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, login)
}
解析 XML 数据:
func bindXML(c *gin.Context) {
var login Login
if err := c.ShouldBindXML(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, login)
}
支持 yaml 格式的数据,使用 c.ShouldBindYAML()。
POST:同时支持多种格式
c.ShouldBind() 支持多种格式的数据,如果请求方法是 GET,那么它按照 form 规则解析 query 参数,如果请求方法是 POST,根据请求头中的 Content-Type 自动选择对应的方法:
func bindALL(c *gin.Context) {
var login Login
if err := c.ShouldBind(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, login)
}
Gin 支持的 Content-Type:
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"