validator默认英文报错,需显式注册中文翻译器并在gin.Default()后立即执行;字段名映射须用完整路径如"Address.City",嵌套校验需加dive标签。

binding:"required"报错但字段名还是英文
这是因为 validator 默认用英文生成错误信息,err.Error() 拿到的是类似 "Key: 'LoginReq.Username' Error: Field validation for 'Username' failed on the 'required' tag" 的原始字符串,没经过翻译。光加 binding:"required" 不等于自动中文提示——必须显式注册中文翻译器,并把字段名映射成可读文本。
注册 zh 翻译器必须在 gin.Default() 之后立即做
validator 实例是懒初始化的,binding.Validator.Engine() 在第一次 c.ShouldBind() 前返回 nil。常见错误是在 init() 函数里调用,或在路由注册后才注册翻译器,导致 panic 或静默失效。
- 在
main()开头、gin.Default()返回 router 后立刻执行注册逻辑 - 先做类型断言:
v, ok := binding.Validator.Engine().(*validator.Validate),ok为 false 就别往下走了 - 用
zh_translations.RegisterDefaultTranslations(v, trans)注册基础规则翻译,trans是ut.Translator实例 - 字段名映射要单独加:
v.RegisterTranslation("Username", trans, func(ut ut.Translator) error { return ut.Add("Username", "用户名", true) })
c.ShouldBind() 和 c.ShouldBindJSON() 错误信息一样,但触发路径不同
两者最终都走 validator 校验,但解析阶段不同:c.ShouldBindJSON() 强制按 JSON 解析,忽略 Content-Type;c.ShouldBind() 则根据请求头自动选绑定器(JSON/form/uri)。如果前端传的是 application/x-www-form-urlencoded 却用了 ShouldBindJSON(),结构体字段压根不会被赋值,binding:"required" 就像没写一样——校验没失效,是字段根本没进结构体。
- GET 请求查参数用
uri:或form:标签,别写json: - POST 表单提交时,结构体字段必须带
form:"field_name",否则c.ShouldBind()找不到对应字段 -
ShouldBind()更通用,但要求结构体标签和实际传输格式严格匹配
自定义字段名翻译容易漏掉嵌套结构体
比如 Address struct{ City string `json:"city" binding:"required"` } 嵌在用户结构体里,validator 默认报错是 "Key: 'User.Address.City'",你只注册了 "City" 翻译,它不认。真正要注册的是完整路径名 "Address.City" 或启用 dive 规则让 validator 进入嵌套层。
- 嵌套字段校验必须加
dive:如Addresses []Address `json:"addresses" binding:"dive,required"` - 翻译嵌套字段名时,用
"Address.City"而不是"City",否则不生效 - 如果嵌套层级深,建议统一用
RegisterFieldNameFunc替换字段路径提取逻辑,避免手动注册爆炸


















