内置规则不够用时怎么加自己的?注册要放在哪里、什么时候生效?规则名写错会在什么时候暴露?这篇从 Engine() 开始,把自定义规则、别名、结构体级校验、TagNameFunc 的坑和整体替换校验器的做法一一试出来。
binding.Validator.Engine() 的类型是 *validator.Validate: true
nil(校验通过)
Req.Day[tag=weekday param=""] Req.End[tag=gtfield param="Start"] Req.Code[tag=code8 param="8"]binding.Validator.Engine().(*validator.Validate) 就是原生的 validator 引擎。RegisterValidation 注册一个 func(fl FieldLevel) bool,RegisterAlias 把一串规则起个名字;跨字段的规则(gtfield=Start)是内置的,可以直接用在 time.Time 上。别名失败时 Tag() 是别名本身。
nil(校验通过)
Range.Tag[tag=startswithx param="ID-"] Range.Max[tag=gtefield_min param=""]
--- 之后才注册 RegisterTagNameFunc:已经校验过的类型 Range 的名字不变,第一次校验的新类型 Range2 用 json 名
Range → Range.Tag[tag=startswithx param="ID-"] Range.Max[tag=gtefield_min param=""]
Range2 → Range2.tag[tag=startswithx param="ID-"]规则可以带参数,在 fl.Param() 里取。需要同时看多个字段时,用 RegisterStructValidation 在 StructLevel 里 ReportError。RegisterTagNameFunc 能让错误里的字段名换成 json 名,但 validator 会缓存每个类型的字段信息:必须在这个类型第一次被校验之前注册,否则对它不生效。
路由注册完成、程序已启动,到这里没有任何报错
第一个请求 → panic: Undefined validation function 'nosuchrule' on field 'Name'
第二个请求 → panic: Undefined validation function 'nosuchrule' on field 'Name'validator 在第一次校验某个结构体时才解析它的 tag。规则名拼错或忘了注册,启动时一切正常,第一个走到这个结构体的请求才会 panic(被 Recovery 捕获成 500)。给每个绑定用的结构体写一个最简单的校验单测,就能在 CI 里提前发现。
自定义校验器第 1 次被调用,拿到 *main.Req
自定义校验器第 2 次被调用,拿到 *main.Req
Validator=nil 时 err=<nil> q={Name:}binding.Validator 是个接口变量,实现 ValidateStruct 与 Engine 两个方法就能替换。设成 nil 则所有绑定都不再校验(binding 标签完全失效),这在测试里有用,在线上是危险的。