validator是结构化数据校验器,只判断数据是否合规,不修改、不清洗、不转换;字段未被反序列化(如json标签不匹配或字段非导出)会导致validate:"required"失效;嵌套结构体需dive,指针/切片需显式处理,错误信息中文需正确注册翻译且字段名精确匹配。

validator 不是“过滤引擎”,它是**结构化数据校验器**——它不修改、不清洗、不转换输入,只回答“这个数据合不合规则”。想靠它做参数过滤(比如自动 trim 字符串、转小写、删空格),会踩坑。
下面直说怎么做、为什么、容易错在哪。
struct tag 里写 validate:"required" 没生效?先看字段有没有被反序列化
常见现象:c.ShouldBindJSON(&req) 返回 nil,但 req.Username 是空字符串,validate:"required" 却没报错。
- 根本原因:字段没被赋值,校验器根本没看到它 ——
json:标签名和请求字段不一致,或字段是私有(首字母小写),Go 反射无法访问 - 必须确保:结构体字段是导出的(大写开头),且
json:标签值与请求字段完全匹配(注意大小写、下划线) - 别信
binding:"required":Gin 的binding标签只用于绑定阶段,不是校验逻辑;真正起作用的是validate:标签 +validator实例 - 示例错误写法:
Username string `json:"username"`→ 前端传{"user_name":"a"},字段就为空,校验跳过
嵌套结构体、指针字段、切片字段校验失败?dive 和 nil 检查不能少
校验器默认只查一层。深层字段(如 User.Profile.Name 或 *Address)不加修饰,直接忽略。
- 嵌套结构体必须加
dive:例如Profile Profile `validate:"dive"` - 指针字段要显式允许 nil:如果
Address *Address是可选的,得写Address *Address `validate:"omitempty,dive"`;否则nil会触发required报错 - 切片字段默认只校验长度,不校验每个元素:要用
dive才进到每个 item,例如Tags []string `validate:"gt=0,dive,required"` - 别依赖
omitempty绕过校验:它只是跳过空值字段,不是“跳过校验”,""或0仍会被required拦住
错误信息返回中文但字段名还是英文?翻译注册顺序错了
validator 默认返回英文错误,即使你用了中文翻译包,也常出现字段名仍是 Username 而不是 “用户名”。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
立即学习“go语言免费学习笔记(深入)”;
- 关键点:翻译注册必须在
validator.New()之后、首次调用Struct()之前完成 - 必须两步都做:
zh.RegisterDefaultTranslations(v, trans)(注册翻译规则) +v.RegisterTranslation("username", trans, func(ut ut.Translator) error { ... })(绑定字段别名) - 别在 handler 里重复注册:每次请求都
RegisterTranslation会 panic - 字段名映射要精确:结构体字段名是
Username,就注册"Username",不是"username"或"user_name"
URL 路径参数和 query 参数怎么用 validator 校验?不能直接绑
validator 只认结构体,chi.URLParam(r, "id") 或 r.URL.Query().Get("page") 返回的是字符串,直接丢给 Validate() 会 panic。
- 路径参数:先用
strconv.ParseInt转类型,再塞进临时结构体校验,例如:type PathID struct{ ID int64 `validate:"required,gte=1"` } - query 参数:用
url.Values构造 map,再用mapstructure.Decode转成结构体,然后校验;别手动一个个if page < 1 - 别把 query 当 JSON 处理:
c.ShouldBindQuery(&q)会尝试按form:标签绑定,但若结构体用的是json:,字段照样为空 - 空字符串、负数、超长数字这些边界值,
validator不会帮你转类型 —— 类型转换必须在它之前做完
最常被忽略的一点:校验器本身不处理类型转换。所有字符串→int、string→time.Time 都得由你手动完成,validator 只在校验前假设“这已经是正确类型的数据”。把转换和校验混在一起,错误堆叠后很难定位到底是解析失败,还是规则写错。

















