beego validation 包不会自动执行结构体标签校验,必须显式调用 valid.valid(&s) 才触发;若结构体含未导出字段或 map[string]string 等不支持类型,验证将静默跳过甚至终止,导致始终返回 true。

Beego 的 validation 包不是“开箱即用”的全自动校验器,它不会自动读取结构体标签并拦截请求——必须显式调用 Valid() 或手动添加规则,否则校验根本不会发生。
结构体标签校验必须配合 Valid() 显式触发
Beego 的 struct tag 校验(如 valid:"Required;Email")不会在 c.ParseForm(&s) 时自动执行。你得主动把结构体传给 validation.Validation{}.Valid() 才会真正跑验证逻辑。
- 错误写法:
c.ParseForm(&user)后直接判断user.Email非空 —— 这只是取值,没走任何校验 - 正确流程:先
c.ParseForm(&user),再valid := validation.Validation{}; ok, _ := valid.Valid(&user) - 注意
Valid()的参数必须是指针(&user),传值会导致字段反射失败,返回ok == true且Errors为空 - 如果结构体里有未导出字段(小写开头)或
map[string]string类型(比如常见的Errors字段),Valid()会静默跳过整个字段,甚至在旧版 Beego(v1.12 及之前)中导致后续所有字段都不校验
GetString() + 手动链式校验适合简单场景
当表单字段少、逻辑轻量(比如登录页只校验 username/password),直接用 c.GetString() 拿值再调 valid.Required() 等方法更直观,也避开结构体反射的坑。
- 每个
valid.Xxx()调用返回一个*validation.Result,可链式调用.Message()自定义提示 - 不要对空字符串做
valid.Range()或valid.Min()—— 这些函数内部不处理空值,会直接跳过;务必先用valid.Required()卡住空值,再校验数值/长度 - 邮箱校验用
valid.Email(email, "email"),但注意它只检查基本格式(a@b.c级别),不发 DNS 查询,也不校验 MX 记录 - 手机号校验没有内置
Mobile()方法,得用valid.Match(phone, "phone").Message("手机号格式错误").Pattern("^1[3-9]\d{9}$")
StructTag 中的 valid 标签语法细节
结构体上的 valid tag 是字符串拼接,不是 Go 表达式,括号和分号必须严格匹配,且函数名大小写敏感。
- 合法写法:
`valid:"Required;Min(1);Max(100);Match(/^\d+$/)"`—— 注意正则斜杠要双写(Go 字符串转义) - 非法写法:
`valid:"required"`(小写)、`valid:"Required, Max(10)"`(逗号非分号)、`valid:"Required(); Email()"`(空括号)都会被忽略 -
Match()和NoMatch()是唯一支持正则的函数,其他如Email、IP、Mobile是独立函数,不能写成Match(/@/)代替Email - 若需自定义逻辑(比如“密码和确认密码一致”),必须让结构体实现
Valid(v *validation.Validation)方法,在里面手动调v.SetError("field", "msg")
常见静默失败原因和绕过方式
Beego validation 最让人头疼的是“没报错,但也没校验”——这通常不是代码写错了,而是类型或可见性问题触发了内部 skip 逻辑。
- 字段类型必须是
string、int、int64、float64、bool、time.Time等基础类型;[]string、map[string]interface{}、struct{}会被完全跳过 - 字段必须首字母大写(导出),
name string不会被扫描,哪怕加了validtag - 最稳妥的绕过方式:把待校验字段单独拎进一个纯净结构体(无嵌套、无 map、全导出字段),错误信息用局部
map[string]string存,别塞进结构体里 - 调试时加一句
fmt.Printf("valid.Errors: %+v ", valid.Errors),如果输出是空 slice,优先查字段类型和导出性,而不是规则写法
Beego validation 的核心限制在于它依赖反射遍历字段,而反射在遇到不可处理类型时选择沉默而非报错——这意味着你永远得自己确保结构体“足够干净”,而不是指望框架告诉你哪错了。











