GolangGinWeb框架4-请求参数绑定和验证

 简介

成都创新互联公司公司2013年成立,公司自成立以来始终致力于为企业提供官网建设、移动互联网业务开发(成都小程序开发、手机网站建设、重庆App定制开发等),并且包含互联网基础服务(域名、主机服务、企业邮箱、网络营销等)应用服务;以先进完善的建站体系及不断开拓创新的精神理念,帮助企业客户实现互联网业务,严格把控项目进度与质量监控加上过硬的技术实力获得客户的一致赞誉。

本文接着上文(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:

 
 
 
 
  1. package main
  2. import (
  3.   "github.com/gin-gonic/gin"
  4.   "net/http"
  5. )
  6. // Binding from JSON
  7. type Login struct {
  8.   User string `form:"user" json:"user" xml:"user"  binding:"required"` //分别定义form,json,xml,binding等标签
  9.   //Password string `form:"password" json:"password" xml:"password" binding:"required"`
  10.   Password string `form:"password" json:"password" xml:"password" binding:"-"`
  11. }
  12. func main() {
  13.   router := gin.Default()
  14.   // Example for binding JSON ({"user": "manu", "password": "123"})
  15.   router.POST("/loginJSON", func(c *gin.Context) {
  16.     var json Login
  17.     if err := c.ShouldBindJSON(&json); err != nil {
  18.       c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  19.       return
  20.     }
  21.     if json.User != "manu" || json.Password != "123" {
  22.       c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
  23.       return
  24.     }
  25.     c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
  26.   })
  27.   // Example for binding XML (
  28.   //  
  29.   //  
  30.   //    user
  31.   //    123
  32.   //  )
  33.   router.POST("/loginXML", func(c *gin.Context) {
  34.     var xml Login
  35.     if err := c.ShouldBindXML(&xml); err != nil {
  36.       c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  37.       return
  38.     }
  39.     if xml.User != "manu" || xml.Password != "123" {
  40.       c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
  41.       return
  42.     }
  43.     c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
  44.   })
  45.   // Example for binding a HTML form (user=manu&password=123)
  46.   router.POST("/loginForm", func(c *gin.Context) {
  47.     var form Login
  48.     // This will infer what binder to use depending on the content-type header.
  49.     if err := c.ShouldBind(&form); err != nil {
  50.       c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  51.       return
  52.     }
  53.     if form.User != "manu" || form.Password != "123" {
  54.       c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
  55.       return
  56.     }
  57.     c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
  58.   })
  59.   // Listen and serve on 0.0.0.0:8080
  60.   router.Run(":8080")
  61. }
  62. //模拟请求: 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)

 
 
 
 
  1. package main
  2. import (
  3.   "net/http"
  4.   "time"
  5.   "github.com/gin-gonic/gin"
  6.   "github.com/gin-gonic/gin/binding"
  7.   "github.com/go-playground/validator/v10"
  8. )
  9. // Booking contains binded and validated data.
  10. // Booking结构中定义了包含绑定器和日期验证器标签
  11. type Booking struct {
  12.   CheckIn  time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`  //登记时间
  13.   CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`  //gtfield=CheckIn表示结账时间必须大于登记时间
  14. }
  15. // 定义日期验证器
  16. var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
  17.   date, ok := fl.Field().Interface().(time.Time)  //利用反射获取到字段值 -> 转为接口 -> 类型断言(时间类型)
  18.   if ok {
  19.     today := time.Now()
  20.     if today.After(date) {  //如果当前时间在checkIn字段时间之后,返回false,即登记时间不能早于当前的时间
  21.       return false
  22.     }
  23.   }
  24.   return true
  25. }
  26. func main() {
  27.   route := gin.Default()
  28.   //对binding.Validator.Engine()接口进行类型断言,断言类型为Validate结构,如果断言成功,就将自定义的验证器注册到Gin内部
  29.   if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
  30.     // - if the key already exists, the previous validation function will be replaced. 该注册方法会将已经存在的验证器替换
  31.     // - this method is not thread-safe it is intended that these all be registered prior to any validation
  32.     // 注册方法不是线程安全的, 在验证开始前,需要保证所有的验证器都注册成功
  33.     v.RegisterValidation("bookabledate", bookableDate)
  34.   }
  35.   route.GET("/bookable", getBookable)
  36.   route.Run(":8085")
  37. }
  38. func getBookable(c *gin.Context) {
  39.   var b Booking
  40.   if err := c.ShouldBindWith(&b, binding.Query); err == nil {
  41.     c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
  42.   } else {
  43.     c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  44.   }
  45. }
  46. //模拟请求:
  47. // 登记时间和结账时间符合条件
  48. //$ curl "localhost:8085/bookable?check_in=2030-04-16&check_out=2030-04-17"
  49. //{"message":"Booking dates are valid!"}
  50. //
  51. // 登记时间在结账时间之后, 不满足gtfield校验规则
  52. //$ curl "localhost:8085/bookable?check_in=2030-03-10&check_out=2030-03-09"
  53. //{"error":"Key: 'Booking.CheckOut' Error:Field validation for 'CheckOut' failed on the 'gtfield' tag"}
  54. //
  55. // 登记时间在当前时间之前,不满足自定义的验证器
  56. //$ curl "localhost:8085/bookable?check_in=2000-03-09&check_out=2000-03-10"
  57. //{"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

新闻标题:GolangGinWeb框架4-请求参数绑定和验证
当前路径:http://www.36103.cn/qtweb/news15/16865.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联