Model
数据解析绑定
- 模型绑定可以将请求体绑定给一个类型。目前Gin支持JSON、XML、YAML和标准表单值的绑定。简单来说,就是根据Body数据类型,将数据赋值到指定的结构体变量中 (类似于序列化和反序列化) 。
- Gin提供了两套绑定方法
- Must bind
- 方法:
Bind
,BindJSON
,BindXML
,BindQuery
,BindYAML
- 行为:这些方法使用MustBindWith。如果存在绑定错误,则用c终止请求,使用
c.AbortWithError (400) .SetType (ErrorTypeBind)
即可。将响应状态代码设置为400,Content-Type header设置为text/plain;charset = utf - 8。请注意,如果在此之后设置响应代码,将会受到警告:[GIN-debug][WARNING] Headers were already written. Wanted to override status code 400 with 422
将导致已经编写了警告[GIN-debug][warning]标头。如果想更好地控制行为,可以考虑使用ShouldBind等效方法。
- 方法:
- Should bind
- 方法:
ShouldBind
,ShouldBindJSON
,ShouldBindXML
,ShouldBindQuery
,ShouldBindYAML
- 行为:这些方法使用
ShouldBindWith
。如果存在绑定错误,则返回错误,开发人员有责任适当地处理请求和错误。
- 方法:
- Must bind
Danger
注意,使用绑定方法时,Gin 会根据请求头中 Content-Type 来自动判断需要解析的类型。如果你明确绑定的类型,你可以不用自动推断,而用 BindWith 方法。 你也可以指定某字段是必需的。如果一个字段被binding:"required"
修饰而值却是空的,请求会失败并返回错误。
JSON绑定
- JSON的绑定,其实就是将request中的Body中的数据按照JSON格式进行解析,解析后存储到结构体对象中。
package main import ( "github.com/gin-gonic/gin" "net/http" ) type Login struct { User string `form:"username" json:"user" uri:"user" xml:"user" binding:"required"` Password string `form:"password" json:"password" uri:"password" xml:"password" binding:"required"` } func main() { router := gin.Default() router.POST("/loginJSON", func(context *gin.Context) { var json Login // 其实就是将request中body的数据按照JSON格式解析到json变量中 if err := context.ShouldBindJSON(&json); err != nil { context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if json.User != "jartin" || json.Password != "admin123" { context.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"}) return } context.JSON(http.StatusOK, gin.H{"status": "login is success"}) }) router.Run(":80") }
jartin@macbookpro1 machine % curl -v -X POST localhost/loginJSON -H 'content-type:application/json' -d '{"user":"jartin","password":"admin123"}' Note: Unnecessary use of -X or --request, POST is already inferred. * Trying 127.0.0.1:80... * Connected to localhost (127.0.0.1) port 80 (#0) > POST /loginJSON HTTP/1.1 > Host: localhost > User-Agent: curl/7.88.1 > Accept: */* > content-type:application/json > Content-Length: 39 > < HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 < Date: Thu, 28 Sep 2023 07:03:25 GMT < Content-Length: 29 < * Connection #0 to host localhost left intact {"status":"login is success"}%
Form表单
- 其实本质是将c中的request中的body数据解析到form中。首先我们先看一下绑定普通表单的例子
- 方法一:对于FORM数据直接使用Bind函数, 默认使用使用form格式解析。
// 绑定普通表单的例子 router.POST("/loginForm", func(context *gin.Context) { var form Login // 方法一:对于FORM数据直接使用Bind函数, 默认使用使用form格式解析,if c.Bind(&form) == nil // 根据请求头中 content-type 自动推断. if err := context.Bind(&form); err != nil { context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if form.User != "jartin" || form.Password != "admin123" { context.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized faild"}) return } context.JSON(http.StatusOK, gin.H{"msg": "login form is success"}) })
- 方法二: 使用BindWith函数,如果你明确知道数据的类型
router.POST("/loginWith", func(context *gin.Context) { var form Login // 你可以显式声明来绑定多媒体表单: // c.BindWith(&form, binding.Form) // 或者使用自动推断: if context.BindWith(&form, binding.Form) == nil { if form.User == "jartin" && form.Password == "admin123" { context.JSON(http.StatusOK, gin.H{"status": "login success"}) } else { context.JSON(http.StatusUnauthorized, gin.H{"status": "login fail"}) } } })
- 方法一:对于FORM数据直接使用Bind函数, 默认使用使用form格式解析。