gin请求数据校验

939496716 · · 1362 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

### 前言 最近优化[gin+vue的前后端分离项目](https://github.com/Bingjian-Zhu/gin-vue-admin)代码时候,发现代码中对请求数据的校验比较繁琐,于是想办法简化它。最终我发现了[go-playground/validator](https://github.com/go-playground/validator)开源库很好用。 ### 优化前代码 代码如下: ![](https://img2020.cnblogs.com/blog/1508611/202004/1508611-20200428135632947-2147280894.png) 发现每个方法都这样校验数据,很繁琐。 ### 优化代码 这里使用[go-playground/validator](https://github.com/go-playground/validator)开源库来简化请求校验。 1.安装`go-playground/validator` ``` # 使用 Go Modules go env -w GO111MODULE=on # 安装 go-playground/validator go get github.com/go-playground/validator/v10 ``` >注意:v10版本是使用Go Modules,运行 `go get github.com/go-playground/validator/v10`前需要确保`GO111MODULE=on`,不然会报:`cannot find package "github.com/go-playground/validator/v10"` 2.实现`StructValidator`接口的两个方法 `StructValidator`是需要实现的最基本的接口,作为验证引擎来确保请求的正确性。 ```go type StructValidator interface { ValidateStruct(interface{}) error Engine() interface{} } ``` * `ValidateStruct` :如果接收到的类型是一个结构体或指向结构体的指针,则执行验证。 * `Engine`: 返回支持`StructValidator`实现的底层验证引擎。 实现接口: ```go package validator import ( "reflect" "sync" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" ) type DefaultValidator struct { once sync.Once validate *validator.Validate } var _ binding.StructValidator = &DefaultValidator{} // ValidateStruct 如果接收到的类型是一个结构体或指向结构体的指针,则执行验证。 func (v *DefaultValidator) ValidateStruct(obj interface{}) error { if kindOfData(obj) == reflect.Struct { v.lazyinit() //如果传递不合规则的值,则返回InvalidValidationError,否则返回nil。 ///如果返回err != nil,可通过err.(validator.ValidationErrors)来访问错误数组。 if err := v.validate.Struct(obj); err != nil { return err } } return nil } // Engine 返回支持`StructValidator`实现的底层验证引擎 func (v *DefaultValidator) Engine() interface{} { v.lazyinit() return v.validate } func (v *DefaultValidator) lazyinit() { v.once.Do(func() { v.validate = validator.New() v.validate.SetTagName("validate") // //v8版本,v8版本使用"binding" // v.validate.SetTagName("binding") }) } func kindOfData(data interface{}) reflect.Kind { value := reflect.ValueOf(data) valueType := value.Kind() if valueType == reflect.Ptr { valueType = value.Elem().Kind() } return valueType } ``` 3.使用该验证引擎 修改`model`,添加`validate`验证 ```go type Article struct { ID int `gorm:"primary_key" json:"id"` State int `json:"state" validate:"min=0,max=1"` TagID int `json:"tag_id" validate:"gt=0"` Title string `json:"title" validate:"required"` Desc string `json:"desc" validate:"required"` Content string `json:"content" validate:"required"` CoverImageURL string `json:"cover_image_url"` CreatedBy string `json:"created_by" validate:"required"` ModifiedBy string `json:"modified_by"` } ``` 最后,只需在`main`函数中添加这行代码: ```go package main import ( "github.com/gin-gonic/gin/binding" "github.com/bingjian-zhu/gin-vue-admin/common/validator" ) func main() { binding.Validator = new(validator.DefaultValidator) // regular gin logic } ``` 以上,我们就完成了gin的数据请求校验了,接下来看下优化后的代码。 ### 优化后代码 ![](https://img2020.cnblogs.com/blog/1508611/202004/1508611-20200428144843346-824677511.png) 只需要正常使用`c.Bing(model)`就可以对请求的数据进行校验了,代码简化了许多。 ### 常用校验规则介绍 ```go type Test struct { ID int `validate:"required"` //数字确保不为0 Name string `validate:"required,min=1,max=8"` //字符串确保不为"",且长度 >=1 && <=8 (min=1,max=8等于gt=0,lt=9) Value string `validate:"required,gte=1,lte=8"` //字符串确保不为"",且长度 >=1 && <=8 Status int `validate:"min=1,max=10"` //最小为0,最大为10(min=0,max=10等于gt=0,lt=11) PhoneNumber string `validate:"required,len=11"` //不为""且长度为11 Time string `validate:"datetime=2006-01-02"` //必须如2006-01-02的datetime格式 Color string `validate:"oneof=red green"` //是能是red或者green Size int `validate:"oneof=37 39 41"` //是能是37或者39或者41 Email string `validate:"email"` //必须邮件格式 JSON string `validate:"json"` //必须json格式 URL string `validate:"url"` //必须url格式 UUID string `validate:"uuid"` //必须uuid格式 } ``` 更多校验规则可以阅读[源码文档](https://github.com/go-playground/validator/blob/master/doc.go)。 ### 总结 [go-playground/validator](https://github.com/go-playground/validator)开源库把gin的请求校验简单化了,使得我们代码更简单易读。 以上只是对结构体做请求校验,对于非结构体的请求校验,用老办法 ```go import "github.com/astaxie/beego/validation" func (a *Article) GetArticle(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) valid := validation.Validation{} valid.Min(id, 1, "id").Message("ID必须大于0") var data *models.Article code := codes.InvalidParams if !valid.HasErrors() { data = a.Service.GetArticle(id) code = codes.SUCCESS } else { for _, err := range valid.Errors { a.Log.Info("err.key: %s, err.message: %s", err.Key, err.Message) } } RespData(c, http.StatusOK, code, data) } ``` 源码地址:https://github.com/Bingjian-Zhu/gin-vue-admin

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1362 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传