您现在的位置是:亿华云 > IT科技类资讯
Golang GinWeb框架4-请求参数绑定和验证
亿华云2025-10-09 12:56:19【IT科技类资讯】2人已围观
简介简介本文接着上文(Golang GinWeb框架3-自定义日志格式和输出方式/启禁日志颜色)继续探索GinWeb框架模型绑定和验证使用模型绑定来绑定请求体到一个Go类型上. 目前支持JSON,XML,
简介
本文接着上文(Golang GinWeb框架3-自定义日志格式和输出方式/启禁日志颜色)继续探索GinWeb框架

模型绑定和验证
使用模型绑定来绑定请求体到一个Go类型上. 目前支持JSON,框架XML,YAML以及标准表单(如foo=bar&boo=baz)的绑定.
Gin使用go-playground/validator/v10包来验证请求, 关于tags在验证中使用详见(https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags)
注意:绑定前请确认结构体中需要绑定的字段标签与绑定类型一致,比如绑定JSON,设置标签: json:"fieldname"
Gin提供两种方式(类型)来完成绑定:
Must bind
1. 方法: Bind, BindJSON, BindXML, BindQuery, BindYAML, BindHeader
2. 特点: 这些方法底层使用MustBindWith方法. 如果出现绑定错误, 请求将以状态码400返回失败信息:c.AbortWithError(400, err).SetType(ErrorTypeBind), 响应中设置Content-Type头为text/plain; charset=utf-8.如果手动设置响应码,会警告响应头已经设置,比如提示: [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422, 如果想要更好的控制这些行为,建议使用下面对应的ShoudBind方法.
Should bind
1. 方法: ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML, ShouldBindHeader
2. 特点: 这些方法底层使用ShouldBindWith. 如果出现绑定错误, 会返回错误, 开发者可以控制和恰当的处理这些错误.
当使用绑定方法时, Gin尝试根据类型头Content-Type header自动推断要使用的绑定器. 如果你已经确认需要绑定的类型,可以直接使用底层的云服务器提供商MustBindWith或ShouldBindWith方法.
你也可以针对特殊的字段指定required标签值, 如果某个字段指定了:binding:"required"标签, 但是在绑定时该字段为空会返回错误.
如以下代码绑定JSON:
package main import ( "github.com/gin-gonic/gin" "net/http" ) // Binding from JSON type Login struct { User string `form:"user" json:"user" xml:"user" binding:"required"` //分别定义form,json,xml,binding等标签 //Password string `form:"password" json:"password" xml:"password" binding:"required"` Password string `form:"password" json:"password" xml:"password" binding:"-"` } func main() { router := gin.Default() // Example for binding JSON ({ "user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login if err := c.ShouldBindJSON(&json); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error()}) return } if json.User != "manu" || json.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{ "status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{ "status": "you are logged in"}) }) // Example for binding XML ( // <?xml version="1.0" encoding="UTF-8"?> // <root> // <user>user</user> // <password>123</password> // </root>) router.POST("/loginXML", func(c *gin.Context) { var xml Login if err := c.ShouldBindXML(&xml); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error()}) return } if xml.User != "manu" || xml.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{ "status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{ "status": "you are logged in"}) }) // Example for binding a HTML form (user=manu&password=123) router.POST("/loginForm", func(c *gin.Context) { var form Login // This will infer what binder to use depending on the content-type header. if err := c.ShouldBind(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error()}) return } if form.User != "manu" || form.Password != "123" { c.JSON(http.StatusUnauthorized, gin.H{ "status": "unauthorized"}) return } c.JSON(http.StatusOK, gin.H{ "status": "you are logged in"}) }) // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } //模拟请求: curl -v -X POST http://localhost:8080/loginJSON -H content-type: application/json -d { "user": "manu", "password": "123" }跳过验证: 与binding:"required"标签对应的是binding:"-", 表示该字段不做绑定, 所以绑定时该字段为空不会报错.
自定义验证器
你也可以自己注册一个自定义验证器, 示例代码请参考(https://github.com/gin-gonic/examples/blob/master/custom-validation/server.go)
package main import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" ) // Booking contains binded and validated data. // Booking结构中定义了包含绑定器和日期验证器标签 type Booking struct { CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` //登记时间 CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` //gtfield=CheckIn表示结账时间必须大于登记时间 } // 定义日期验证器 var bookableDate validator.Func = func(fl validator.FieldLevel) bool { date, ok := fl.Field().Interface().(time.Time) //利用反射获取到字段值 -> 转为接口 -> 类型断言(时间类型) if ok { today := time.Now() if today.After(date) { //如果当前时间在checkIn字段时间之后,返回false,即登记时间不能早于当前的时间 return false } } return true } func main() { route := gin.Default() //对binding.Validator.Engine()接口进行类型断言,断言类型为Validate结构,如果断言成功,就将自定义的验证器注册到Gin内部 if v, ok := binding.Validator.Engine().(*validator.Validate); ok { // - if the key already exists, the previous validation function will be replaced. 该注册方法会将已经存在的亿华云验证器替换 // - this method is not thread-safe it is intended that these all be registered prior to any validation // 注册方法不是线程安全的, 在验证开始前,需要保证所有的验证器都注册成功 v.RegisterValidation("bookabledate", bookableDate) } route.GET("/bookable", getBookable) route.Run(":8085") } func getBookable(c *gin.Context) { var b Booking if err := c.ShouldBindWith(&b, binding.Query); err == nil { c.JSON(http.StatusOK, gin.H{ "message": "Booking dates are valid!"}) } else { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error()}) } } //模拟请求: // 登记时间和结账时间符合条件 //$ curl "localhost:8085/bookable?check_in=2030-04-16&check_out=2030-04-17" //{ "message":"Booking dates are valid!"} // // 登记时间在结账时间之后, 不满足gtfield校验规则 //$ curl "localhost:8085/bookable?check_in=2030-03-10&check_out=2030-03-09" //{ "error":"Key: Booking.CheckOut Error:Field validation for CheckOut failed on the gtfield tag"} // // 登记时间在当前时间之前,不满足自定义的验证器 //$ curl "localhost:8085/bookable?check_in=2000-03-09&check_out=2000-03-10" //{ "error":"Key: Booking.CheckIn Error:Field validation for CheckIn failed on the bookabledate tag"}%另外结构体级别的验证采用如下的方式注册, v.RegisterStructValidation(UserStructLevelValidation, User{ }), 请参考struct-lvl-validation example(https://github.com/gin-gonic/examples/tree/master/struct-lvl-validations)
参考文档
Gin官方仓库:https://github.com/gin-gonic/gin
很赞哦!(464)
相关文章
- 4、待所有域名查询结束后可在右侧点击导出结果,即可以excel的文件方式将查询到的结果导出。
- 我终于搞清楚了和String有关的那点事儿
- 程序员能不能一直纯靠技术生存
- Java 的双重分发与 Visitor 模式
- 4、企业无形资产:通用网站已成为企业网络知识产权的重要组成部分,属于企业的无形资产,也有助于提升企业的品牌形象和技术领先形象。它是企业品牌资产不可或缺的一部分。
- 不理解Zookeeper一致性原理,谈何异地多活改造
- API难解释?这次用啤酒和积木来破局
- 小伙在某知名公司的Python面试题详解,希望对各位以后面试有帮助
- 在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
- 管理员百宝箱:节省时间的10款杀手级工具
热门文章
站长推荐
当投资者经过第二阶段的认真学习之后又充满了信心,认为自己可以在市场上叱咤风云地大干一场了。但没想到“看花容易绣花难”,由于对理论知识不会灵活运用.从而失去灵活应变的本能,就经常会出现小赢大亏的局面,结果往往仍以失败告终。这使投资者很是困惑和痛苦,不知该如何办,甚至开始怀疑这个市场是不是不适合自己。在这种情况下,有的人选择了放弃,但有的意志坚定者则决定做最后的尝试。
沙龙 | 邀您与国美/AWS/转转三位专家共同探讨小程序电商实战
HTTP 内容编码,也就这 2 点需要知道 | 实用 HTTP
【WOT2018】郑长帅:揭秘摩拜国际化背后的IoT技术支撑
四、长串数字域名
如何优雅使用Docker?请收下这15个快捷有效的小技巧
复用的着相
DCloud崔红保:基于Vue技术开发微信小程序和原生App