当下主流的web服务都做了前后端分离处理,前端和后端之间只需定义好通信的API接口,各自按照restful规范进行业务开发,大大降低了需求开发的周期,但数据表单校验也成为必不可少的安全处理流程。
事实上,我之前负责维护的一个后端微服务就出现测试人员通过API调用时,传入错误数据,导致后端服务数据异常的案例。因此,抽空学习了validator第三方数据校验库。这个库的使用方法网上有很多,这里我只记录一下结合实际echo框架的一些使用场景。

1、自定义字段级别的数据校验

使用场景: 结构体Job中含有的Report字段类型是一个自定义的数据类型(本质是个string数组),正常场景只接收 “xlsx” 和 “html” 这两个字符串。如果需要对这个自定义的字段添加校验函数,方法如下:

  1. type Job struct {
  2. ID uuid.UUID
  3. Name string
  4. Report pq.StringArray
  5. }
  6. func TaskReportValidation(fl validator.FieldLevel) bool {
  7. reportTypes := fl.Field().Interface().(pq.StringArray)
  8. for _, val := range reportTypes {
  9. if val != "xlsx" && val != "html" {
  10. return false
  11. }
  12. }
  13. return true
  14. }

2、自定义结构体级别的数据校验

使用场景: model包中有个结构体Scene,该结构体中的字段大多是自定义的,如果需要对这些字段进行数据校验,可以一个个编写字段级别的校验函数(有点麻烦),也可以对Scene结构体整体进行校验。方法如下:

  1. func SceneStructureValidation(sl validator.StructLevel) {
  2. // get scene instance
  3. scene := sl.Current().Interface().(model.Scene)
  4. // scene实例中需要校验的字段,需要自行编写校验逻辑
  5. ...
  6. }

3、将validator集成到echo中

echo本身没有实现输入数据校验的功能,但是提供了一个校验接口,我们只需实现echo提供的接口即可。

  1. type CustomValidate struct {
  2. once sync.Once
  3. validator *validator.Validate
  4. }
  5. // 实现 echo 提供的接口 Validate
  6. func (c *CustomValidate) Validate(i interface{}) error {
  7. c.lazyInit()
  8. return c.validate.Struct(i)
  9. }
  10. // 因为 validator.Validate 实例化做了不少事,这里使用sync.Once将实例化推迟到使用时。
  11. func (c *CustomValidate) lazyInit() {
  12. c.once.Do(func() {
  13. c.validator = validator.New()
  14. // 注册 TaskReportValidation
  15. _ = c.validator.RegisterValidation("check_report_type", TaskReportValidation)
  16. // 注册 SceneStructureValidation
  17. c.validator.RegisterStructValidation(SceneStructureValidation, model.Scene)
  18. })
  19. }
  20. // ==== 与echo集成
  21. e := echo.New()
  22. e.Validator = &CustomValidate{}
  23. // 之后就可以在需要进行表单校验的地方通过 ctx.Validate() 进行校验。

参考文章

1. validator官方使用手册
2. 自定义validator,进行输入校验
3. Go 每日一库之 validator