直接用 validator.RegisterValidation 注册正则函数即可,但需同步注册中文翻译器、添加 label 标签并调用 Translate 方法,才能将默认英文错误“Key: 'User.Phone' failed on 'phone' tag”转化为“手机号格式不正确”。

直接用 validator.RegisterValidation 注册正则函数就行,但默认错误提示是英文、字段名裸露、不带上下文——这在生产环境几乎没法用。
为什么内置的 email 校验不够用
它只覆盖标准邮箱格式,没法处理业务定制需求:比如「必须是公司域名邮箱」「手机号需符合 1[3-9]\d{9}」「订单号必须以 ORD 开头 + 8 位数字」。这些都得靠自定义正则,而 email 标签本身不接受参数,也没法复用。
-
email是硬编码规则,不能改正则表达式 - 无法区分「邮箱格式错」和「域名白名单不匹配」两类错误
- 错误信息固定为
Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag,前端没法友好展示
注册带中文提示的正则校验器(phone 示例)
关键不是写正则,而是让错误能被翻译、字段能被标注、提示能带业务语义。以下代码必须放在 init() 或服务启动早期:
func init() {
v, ok := binding.Validator.Engine().(*validator.Validate)
if !ok {
return
}
v.RegisterValidation("phone", func(fl validator.FieldLevel) bool {
val := fl.Field().String()
return regexp.MustCompile(`^1[3-9]\d{9}$`).MatchString(val)
})
// 必须同时注册翻译,否则还是英文
zhT := zh.New()
uni := ut.New(zhT, zhT)
trans, _ := uni.GetTranslator("zh")
zh_trans.RegisterDefaultTranslations(v, trans)
}
- 正则逻辑写在闭包里,
fl.Field().String()拿到原始值,别用fl.Param() - 注册翻译器必须在
RegisterValidation之后,否则中文提示不生效 - 字段标签里写
binding:"required,phone",不是binding:"required,regexp=..."
ShouldBindJSON 报错时字段名丢失怎么办
默认错误结构体里只有 Field(如 User.Phone),没有你想要的「手机号」这种可读名。要解决,得改 validator 的 tag 解析方式:
- 给结构体字段加
label:"手机号"标签:Phone string `json:"phone" binding:"required,phone" label:"手机号"` - 在
init()里调用v.RegisterTagNameFunc,把label当作显示名来源 - 错误处理时用
err.(validator.ValidationErrors).Translate(trans)才能拿到带「手机号」的提示 - 别依赖
err.Error(),它永远返回原始字段路径
真正麻烦的不是写正则,而是让错误从「Key: 'User.Phone' failed on 'phone' tag」变成「手机号格式不正确」——这中间差一个 translator 初始化时机、一个 label 标签、一次 Translate 调用,漏任何一个,前端就只能猜字段含义。


















