Beego的valid包需手动调用Valid()校验,先ParseForm/JSON并检查错误,再用valid.Validation实例校验带valid tag的结构体字段,自定义函数须在启动前注册。

Beego 的 valid 包校验怎么用最省事
Beego 自带的 valid 包不是装饰器式自动触发,必须手动调用 valid.Valid() 才会执行字段校验。不调就等于没写——这是新手掉进最多的一次坑。
典型用法是:在 Controller 方法里,先绑定参数(c.ParseForm() 或 c.ParseJSON()),再实例化 valid.Validation,最后遍历结构体字段校验:
v := valid.Validation{}
b, _ := v.Valid(&user)
if !b {
for _, err := range v.Errors {
// err.Key 是字段名,err.Message 是提示
beego.Error(err.Key, err.Message)
}
}
- 结构体字段必须带
validtag,比如json:"name" valid:"Required;Min(2)" -
Required校验的是零值(空字符串、0、nil),不是非空字符串;若要排除空白字符串,得加Match(/^.+$/) - 自定义错误信息可写在 tag 里:
valid:"Required(ErrorMessage('用户名必填')",但注意括号不能嵌套,否则 panic
JSON 请求体校验失败时,ParseJSON() 不报错但 Valid() 会漏字段
当 POST JSON 数据中包含结构体未定义的字段,c.ParseJSON() 默认静默忽略;但若字段名拼错或类型不匹配(比如传了字符串给 int 字段),反序列化会失败,此时 &user 处于零值状态,Valid() 会把所有 Required 字段都判为错误——看起来像“全错”,实际是解析阶段已崩。
- 务必检查
c.ParseJSON()返回 error:if err := c.ParseJSON(&user); err != nil { c.Abort("400") } - 推荐在 Parse 后立刻打日志:
beego.Debug("parsed user:", user),确认字段是否真被赋值 - 对时间字段(
time.Time),JSON 传"2024-01-01"会解析失败,需前端传 RFC3339 格式("2024-01-01T00:00:00Z")或后端改用string+ 自定义 UnmarshalJSON
如何让校验错误直接返回 JSON 格式响应
Beego 默认不提供统一错误响应格式,v.Errors 是 slice,需要手动转成 map 或 struct 再 c.Data["json"] = ... 输出。
建议封装一个快捷函数:
func ValidationErrors(v *valid.Validation) map[string]string {
m := make(map[string]string)
for _, err := range v.Errors {
m[err.Key] = err.Message
}
return m
}
- 调用后直接:
c.Data["json"] = ValidationErrors(&v); c.ServeJSON() - 别用
c.AbortWithStatusJSON(400, ...),它会跳过模板渲染但也会跳过ServeJSON的 Content-Type 设置,导致前端收到 text/plain - 如果项目用了 Swagger,字段名(
err.Key)要和 API 文档里的参数名一致,否则联调时对不上
自定义校验函数注册后不生效?注意作用域和初始化时机
用 valid.RegisterCustomFunc 注册的函数,必须在 Beego 应用启动前完成(比如 main.go 的 init() 或 main() 开头),且函数签名必须严格为 func(string) bool 或 func(interface{}) bool。
- 常见错误:在某个 Controller 里注册,结果只有该请求生效,下一次请求就没了
- 函数名不能含点号或特殊字符,否则 tag 解析失败,例如
valid:"MyEmailCheck"可以,valid:"check.email"不行 - 若校验逻辑依赖 DB 或缓存,不要在自定义函数里直接查——
Valid()是同步阻塞调用,会拖慢整个请求;应拆到校验后、业务逻辑前单独处理
Beego 的校验链路短而直接,但每个环节都要求显式控制。最容易被忽略的是:解析失败和校验失败是两件事,得分开捕获;还有就是自定义函数的注册位置,一错就全程静默失效。











