Query/Param/PostForm/GetHeader 参数族怎么选
结论先行
选参数 API 的唯一依据是参数来源:路由段用 c.Param,URL 查询串用 c.Query 一族,表单/请求体用 c.PostForm 一族,请求头用 c.GetHeader。字段一多(或要校验)就别逐个取,改用 ShouldBindQuery / ShouldBind 配合 form tag 一把梭。
来源对照表
| API 族 | 来源 | 缺失时的行为 | 常用变体 |
|---|---|---|---|
| c.Param("id") | 路由 /users/:id | 取不到(说明路由没匹配上) | 无 |
| c.Query("q") | URL ?q= | 空串 | DefaultQuery(给默认值)、GetQuery(返回是否存在) |
| c.PostForm("f") | POST body(urlencoded / multipart) | 空串 | DefaultPostForm、GetPostForm |
| c.GetHeader("X") | 请求头(大小写不敏感) | 空串 | 无 |
| 多值 | ?tag=a&tag=b | — | c.QueryArray / c.GetQueryArray |
注意点
c.Query("k")与?k=(空值)都返回空串,无法区分“没传”与“传了空”——需要区分时用带 ok 返回的GetQuery/GetPostForm。c.Param只对通配路由有效;参数是否合法(如非数字 id)需要自己校验,路由只管切字符串。- 请求头没有“默认值”写法,自己判空即可;不要用 Header 传业务主数据。
- 表单字段较多或含结构时,绑定比逐个 Get 更省事且能顺带校验。
- GET 方法用 ShouldBindQuery 只读查询串;POST 表单想“查询串 + body 一起绑”的取舍见官方 FAQ(以官方文档为准)。
代码示例
r.GET("/search", func(c *gin.Context) {
q := c.DefaultQuery("q", "all") // 缺省值
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
if v, ok := c.GetQuery("strict"); ok && v == "1" { /* 传了 strict=1 */ }
c.JSON(200, gin.H{"q": q, "page": page})
})
r.POST("/login", func(c *gin.Context) {
name := c.PostForm("name")
token := c.GetHeader("Authorization")
_ = name; _ = token
})
// 结构化写法(推荐)
type SearchReq struct {
Q string `form:"q" binding:"required"`
Page int `form:"page" binding:"gte=1"`
}
// c.ShouldBindQuery(&req)
常见追问 / 记忆点
- 追问:为什么不用 r.URL.Query() 直接取?答:可以,但 c.Query 一族做了惰性解析与默认值封装,语义更清晰;框架 API 优先。
- 追问:表单 POST 里同时有 query 和 body 字段怎么取?答:Query 取 URL、PostForm 取 body,两者不互相覆盖。
- 记忆点:先问“参数从哪来”,再选 Param/Query/PostForm/Header;多字段上绑定。