go数据校验与清洗需分离:govalidator专用于单字段字符串清洗与轻量验证,validator/v10专用于结构体声明式校验;struct校验必须传指针,dive需紧跟类型tag,omitempty与required冲突,time.time和指针字段需显式约束,清洗应在校验前完成。

Go 里做数据校验与清洗,别混用 govalidator 和 validator/v10 —— 前者适合单字段字符串清洗+轻量验证(比如 trim、email 格式),后者才是结构体级声明式校验的主力;两者定位不同,强行套用会导致规则分散、错误难定位、time.Time 或指针字段静默失效。
struct 校验必须传指针,且标签顺序影响 dive 是否生效
传值调用 Validate.Struct(user) 看似自然,但反射无法读取 struct tag,结果是“没报错也没校验”,极易误判为逻辑正常。必须传指针:Validate.Struct(&user)。
-
dive只对切片/Map 生效,且必须紧跟在类型 tag 后:正确写法是validate:"min=1,dive,required";写成validate:"required,dive"会被忽略 - 嵌套结构体字段若没加
validate标签,即使顶层加了embedded,子字段也不会被校验 -
omitempty不是校验规则,它让 validator 跳过该字段——和required天然冲突,别一起用
正则校验别硬写 regexp.MustCompile,优先复用 govalidator 内置函数
自己写 regexp.MustCompile(`^[a-zA-Z0-9_]{3,20}$`) 容易漏转义、难维护,而 govalidator 已封装常用模式,比如:
-
govalidator.IsAlphanumeric替代字母数字下划线正则 -
govalidator.IsEmail比手写邮箱正则更健壮(处理 IDN、长域名等边界) -
govalidator.IsChinese底层用\p{Han},比[\u4e00-\u9fa5]更准
自定义正则只在业务强特异性时才写,且务必用 regexp.Compile(带 error 检查),别用 MustCompile——上线后 panic 比校验失败更致命。
time.Time 和指针字段的校验陷阱最常导致漏检
time.Time 零值是 0001-01-01,validate:"required" 完全不触发;*string 的 required 检的是指针是否为 nil,不是解引用后的值是否为空。
- 时间字段必须显式约束:用
validate:"required,datetime=2006-01-02T15:04:05Z"或预处理为time.Parse后再校验 - 指针类型字段若允许为空,别用
required;若业务上非空,校验前先判if u.Name == nil,再解引用校验内容 -
[]string空切片[]是合法值,required不报错;需min=1或配合dive校验每个元素
清洗和校验要分两步走,不能靠一个库包打天下
校验是“判断是否合法”,清洗是“把不合法变合法”——比如前端传来 " john@EXAMPLE.COM ",govalidator 的 Trim、ToLowerCase、StripTags 是清洗动作;validator 的 email、min=3 是校验动作。两者混合会导致逻辑混乱。
- 清洗放在 JSON Unmarshal 之后、校验之前:先
govalidator.Truncate截断超长字段,再validator.Struct - 不要在
Validate()方法里做清洗(如自动补默认值),这违反单一职责,也破坏幂等性 - 清洗失败应返回明确错误(如 “phone too long after trim”),而不是吞掉或静默截断
真正难的不是写对那几行 tag 或正则,而是分清哪一步该“改数据”,哪一步该“拒数据”。混淆这两者,后期 debug 时你会花三倍时间找问题源头。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











