表单和查询绑定

除了 JSON,Gin 也支持绑定查询参数和表单数据。

一、查询参数绑定

请求:

GET /users?page=1&pageSize=10&keyword=tom

结构体:

type UserQuery struct {
	Page     int    `form:"page"`
	PageSize int    `form:"pageSize"`
	Keyword  string `form:"keyword"`
}

处理函数:

func listUsers(c *gin.Context) {
	var query UserQuery
	if err := c.ShouldBindQuery(&query); err != nil {
		c.JSON(400, gin.H{"message": err.Error()})
		return
	}

	c.JSON(200, gin.H{"query": query})
}

查询参数使用 form 标签,不是 json 标签。

二、表单绑定

HTML 表单或 application/x-www-form-urlencoded 可以这样绑定:

type LoginForm struct {
	Username string `form:"username"`
	Password string `form:"password"`
}

处理函数:

func login(c *gin.Context) {
	var form LoginForm
	if err := c.ShouldBind(&form); err != nil {
		c.JSON(400, gin.H{"message": err.Error()})
		return
	}

	c.JSON(200, gin.H{
		"username": form.Username,
	})
}

注册:

router.POST("/login", login)

三、JSON 和表单共用结构体

有些接口既想支持 JSON,也想支持表单,可以同时写标签:

type LoginRequest struct {
	Username string `json:"username" form:"username"`
	Password string `json:"password" form:"password"`
}

然后使用:

if err := c.ShouldBind(&req); err != nil {
	c.JSON(400, gin.H{"message": err.Error()})
	return
}

ShouldBind 会根据请求的 Content-Type 自动选择绑定方式。

四、初学建议

前后端分离接口建议优先使用 JSON。

常见约定:

场景推荐
新增、修改数据JSON 请求体
列表分页、搜索查询参数
上传文件multipart form

不要把所有参数都塞进查询字符串,也不要把分页参数放到 JSON 请求体里,保持接口语义清楚。