本文最后更新于:1 年前
一、模式绑定 若要将请求主体绑定到结构体中,请使用模型绑定,目前支持JSON、XML、YAML和标准表单值(foo=bar&boo=baz)的绑定。
需要在绑定的字段上设置tag,比如,绑定格式为json,需要这样设置 json:”fieldname” 。
Gin还提供了两套绑定方法:
1、Must bind
Methods - Bind, BindJSON, BindXML, BindQuery, BindYAML
Behavior - 这些方法底层使用 MustBindWith,如果存在绑定错误,请求将被以下指令中止 c.AbortWithError(400, err).SetType(ErrorTypeBind),响应状态代码会被设置为400,请求头Content-Type被设置为text/plain; charset=utf-8。注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422,如果你希望更好地控制行为,请使用ShouldBind相关的方法
来看看MustBindWith方法实现
1 2 3 4 5 6 7 8 9 func (c *Context) MustBindWith(obj any, b binding.Binding) error { if err := c.ShouldBindWith(obj, b); err != nil { c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) return err } return nil }
我们可以看到MustBindWith的方法调用的是ShouldBindWith方法,判断是否绑定错误,错误则返回404。
2、Should bind
Methods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML
Behavior - 这些方法底层使用 ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。
来看看ShouldBindWith方法实现
1 2 3 4 func (c *Context) ShouldBindWith(obj any, b binding.Binding) error { return b.Bind(c.Request, obj) }
1)ShouldBindJSON方法 ShouldBindJSON是c.ShouldBindWith(obj, binding.JSON)的快捷方式。
JSON绑定结构体:
1 2 3 4 5 type PostParams struct { Name string `json:"name"` Age int `json:"age"` Sex bool `json:"sex"` }
ShouldBindJSON代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func main () { r := gin.Default() r.POST("/testBind/" , func (c *gin.Context) { var p PostParams err := c.ShouldBindJSON(&p) fmt.Printf("p: %v\n" , p) if err != nil { fmt.Println(err) c.JSON(404 , gin.H{ "msg" : "报错了" , "data" : gin.H{}, }) } else { c.JSON(200 , gin.H{ "msg" : "成功了" , "data" : p, }) } }) r.Run(":8080" ) }
打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind
如果我们发送的JSON里少一项或者跟结构体的属性名不对应会如何? 答案是:没有被成功绑定的属性则为空。
2)ShouldBindUri方法 ShouldBindUri使用指定的绑定引擎绑定传递的struct指针。
Uri绑定结构体:
1 2 3 4 5 type PostParams struct { Name string `uri:"name"` Age int `uri:"age"` Sex bool `uri:"sex"` }
ShouldBindUri代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func main () { r := gin.Default() r.POST("/testBind/:name/:age/:sex" , func (c *gin.Context) { var p PostParams err := c.ShouldBindUri(&p) fmt.Printf("p: %v\n" , p) if err != nil { fmt.Println(err) c.JSON(404 , gin.H{ "msg" : "报错了" , "data" : gin.H{}, }) } else { c.JSON(200 , gin.H{ "msg" : "成功了" , "data" : p, }) } }) r.Run(":8080" ) }
打开postman选择POST请求,选择uri里面输入对应的数据,访问http://localhost:8080/testBind/linzy/23/true
3)ShouldBindQuery方法 ShouldBindQuery是c.ShouldBindWith(obj, binding.Query)的快捷方式
Query绑定结构体:
1 2 3 4 5 type PostParams struct { Name string `form:"name"` Age int `form:"age"` Sex bool `form:"sex"` }
ShouldBindQuery代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func main () { r := gin.Default() r.POST("/testBind" , func (c *gin.Context) { var p PostParams err := c.ShouldBindQuery(&p) fmt.Printf("p: %v\n" , p) if err != nil { fmt.Println(err) c.JSON(404 , gin.H{ "msg" : "报错了" , "data" : gin.H{}, }) } else { c.JSON(200 , gin.H{ "msg" : "成功了" , "data" : p, }) } }) r.Run(":8080" ) }
打开postman选择POST请求,选择Params输入数据,访问http://localhost:8080/testBind?name=linzy&age=23&sex=true
当我们使用绑定方法时,Gin会根据Content-Type推断出使用哪种绑定器,如果你确定你绑定的是什么,你可以使用MustBindWith或者BindingWith。
二、参数验证器 我们可以给字段指定特定规则的修饰符,如果一个字段用binding:”required”修饰,并且在绑定时该字段的值为空,那么将返回一个错误。
1、结构体验证器 用gin框架数据验证,可以不用解析数据,来if-else判断,整体使代码精简了很多。 binding:”required就是gin自带的数据验证,表示数据不为空,为空则返回错误。
定义结构体:
1 2 3 4 5 6 type PostParams struct { Name string `json:"name"` Age int `json:"age" binding:"required,gt=10"` Sex bool `json:"sex"` }
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func main () { r := gin.Default() r.POST("/testBind" , func (c *gin.Context) { var p PostParams err := c.ShouldBindJSON(&p) fmt.Printf("p: %v\n" , p) if err != nil { fmt.Println(err) c.JSON(404 , gin.H{ "msg" : "报错了" , "data" : gin.H{}, }) } else { c.JSON(200 , gin.H{ "msg" : "成功了" , "data" : p, }) } }) r.Run(":8080" ) }
打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind
我们成功通过数据验证,拿到了数据。
出现错误,数据不正确。
2、自定义数据验证 对绑定解析到结构体上的参数,自定义验证功能。比如我们想name不为空的同时,不能为admin的时候,就无法 binding 现成的方法。
JSON结构体:
1 2 3 4 5 6 7 type PostParams struct { Name string `json:"name" binding:"required,notAdmin"` Age int `json:"age"` Sex bool `json:"sex"` }
自定义的校验方法:
1 2 3 4 5 6 7 8 9 func notAdmin (v validator.FieldLevel) bool { if v.Field().Interface().(string ) == "admin" { return false } return true }
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 func main () { r := gin.Default() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("notAdmin" , notAdmin) } r.POST("/testBind" , func (c *gin.Context) { var p PostParams err := c.ShouldBindJSON(&p) fmt.Printf("p: %v\n" , p) if err != nil { fmt.Println(err) c.JSON(404 , gin.H{ "msg" : "name 不能为admin" , "data" : gin.H{}, }) } else { c.JSON(200 , gin.H{ "msg" : "成功了" , "data" : p, }) } }) r.Run(":8080" ) }
打开postman选择POST请求,选择Body里的raw上传JSON格式的数据,访问http://localhost:8080/testBind
自定义数据验证检验出数据错误,并返回请求一个错误。
大功告成!通过了自定义数据验证,并成功返回了。