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=bc.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;多字段上绑定。
笔记加载中…