模型绑定是把请求参数自动映射到结构体的过程。不用再手写一堆解析代码了。
Gin 提供了两类绑定方法:
绑定失败返回错误,不会自动返回响应:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
r.POST("/users", func(c *gin.Context) {
var user User
if err := c.ShouldBind(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
})
绑定失败自动返回 400 响应:
r.POST("/users", func(c *gin.Context) {
var user User
if err := c.Bind(&user); err != nil {
return
}
c.JSON(200, user)
})
推荐使用 ShouldBind 系列,可以自定义错误响应。
ShouldBind 会根据 Content-Type 自动选择绑定方式:
| Content-Type | 绑定方法 |
|---|---|
| application/json | ShouldBindJSON |
| application/xml | ShouldBindXML |
| application/x-www-form-urlencoded | ShouldBind |
| multipart/form-data | ShouldBind |
可以显式指定绑定来源:
var user User
c.ShouldBindJSON(&user)
c.ShouldBindXML(&user)
c.ShouldBindQuery(&user)
c.ShouldBindUri(&user)
c.ShouldBindHeader(&user)
结构体标签告诉 Gin 如何映射参数:
type User struct {
Name string `json:"name" form:"name" xml:"name"`
Email string `json:"email" form:"email" xml:"email"`
Age int `json:"age" form:"age" xml:"age"`
}
| 标签 | 用途 |
|---|---|
| json | JSON 绑定 |
| form | 表单绑定 |
| xml | XML 绑定 |
| binding | 验证规则 |
| uri | URI 参数绑定 |
type SearchParams struct {
Query string `form:"q"`
Page int `form:"page"`
Size int `form:"size"`
}
r.GET("/search", func(c *gin.Context) {
var params SearchParams
if err := c.ShouldBindQuery(¶ms); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, params)
})
访问 /search?q=golang&page=1&size=10,参数会自动绑定。
type UserParams struct {
ID string `uri:"id" binding:"required"`
}
r.GET("/users/:id", func(c *gin.Context) {
var params UserParams
if err := c.ShouldBindUri(¶ms); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"user_id": params.ID})
})
type Headers struct {
Token string `header:"Authorization"`
Language string `header:"Accept-Language"`
}
r.GET("/info", func(c *gin.Context) {
var headers Headers
if err := c.ShouldBindHeader(&headers); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, headers)
})
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type CreateUserRequest struct {
Name string `json:"name" form:"name" binding:"required"`
Email string `json:"email" form:"email" binding:"required,email"`
Age int `json:"age" form:"age" binding:"gte=0,lte=150"`
}
type GetUserParams struct {
ID string `uri:"id" binding:"required"`
}
type SearchQuery struct {
Query string `form:"q" binding:"required"`
Page int `form:"page" binding:"gte=1"`
Size int `form:"size" binding:"gte=1,lte=100"`
}
func main() {
r := gin.Default()
r.POST("/users", createUser)
r.GET("/users/:id", getUser)
r.GET("/search", search)
r.Run(":8080")
}
func createUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBind(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{
"message": "用户创建成功",
"user": req,
})
}
func getUser(c *gin.Context) {
var params GetUserParams
if err := c.ShouldBindUri(¶ms); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"id": params.ID,
"name": "User " + params.ID,
})
}
func search(c *gin.Context) {
var query SearchQuery
if err := c.ShouldBindQuery(&query); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"query": query.Query,
"page": query.Page,
"size": query.Size,
})
}
这一章学习了:
ShouldBind 和 Bind 的区别