跳到主要内容

验证

VEF 以 go-playground/validator 为基础验证引擎,并在其上叠加了框架自己的行为:

  • 翻译后的错误消息
  • label / label_i18n 支持
  • 自定义验证规则
  • 对框架 null 包装类型的支持

验证入口

typed params 和 typed meta 在解码完成后会自动验证。框架内部调用的是:

validator.Validate(value)

这意味着只要 handler 参数使用 typed 请求结构体,就默认带有验证能力,不需要在 handler 里手工再调一次。

标准 Validator 标签

VEF 直接继承 go-playground/validator 的标准标签集合。常见标签例如:

标签含义示例
required字段必须存在且非零值validate:"required"
email字段必须是合法邮箱validate:"required,email"
min数值或长度下界validate:"min=1"
max数值或长度上界validate:"max=32"
oneof字段必须属于候选值集合validate:"oneof=admin user guest"
len精确长度validate:"len=32"
omitempty字段为空时跳过后续校验validate:"omitempty,email"
dive对 slice 或 map 的每个元素继续校验validate:"required,dive"

VEF 不会重写这些上游规则,它做的是在其上增加框架自定义规则。

标签名解析

验证错误在可能的情况下会优先使用标签名,而不是原始 Go 字段名。

解析顺序如下:

来源效果
label:"..."直接使用显式标签文本
label_i18n:"..."先经过 i18n 翻译,再回退到字段名
都没有使用 Go 字段名

示例:

type UserParams struct {
api.P

Username string `json:"username" validate:"required" label:"Username"`
Phone string `json:"phone" validate:"phone_number" label_i18n:"user_phone"`
}

内置自定义规则

VEF 当前内置了以下自定义验证规则:

规则标签期望字段类型含义示例
phone_numberstring校验中国大陆手机号validate:"phone_number"
dec_min=<value>decimal.Decimal小数值必须大于等于给定阈值validate:"dec_min=0"
dec_max=<value>decimal.Decimal小数值必须小于等于给定阈值validate:"dec_max=999.99"
alphanum_usstring只允许字母、数字、下划线validate:"alphanum_us"
alphanum_us_slashstring只允许字母、数字、下划线和斜线validate:"alphanum_us_slash"
alphanum_us_dotstring只允许字母、数字、下划线和点validate:"alphanum_us_dot"

phone_number

规则说明
接受的值1[3-9]\\d{9}
主要用途手机号输入校验
常见报错语义“格式不正确”

dec_min / dec_max

规则说明
支持的字段类型decimal.Decimal
参数格式十进制字符串,例如 10.5
行为把字段值与解析后的 decimal 阈值比较

alphanum_us

规则允许字符
alphanum_us字母、数字、_
alphanum_us_slash字母、数字、_/
alphanum_us_dot字母、数字、_.

常见用途:

规则常见用途
alphanum_usaction name、简单标识、代码值
alphanum_us_slashRPC resource name、斜杠分段标识
alphanum_us_dot文件名、模块名、点分标识

支持的 Null 类型

VEF 已注册自定义 type func,因此以下 null 包装类型都能正确参与验证:

支持的 null 类型
null.String
null.Int
null.Int16
null.Int32
null.Float
null.Bool
null.Byte
null.DateTime
null.Date
null.Time
null.Decimal

实际效果:

  • 当 null 包装值有效时,校验作用于内部真实值
  • 当 null 包装值无效时,该值会被视为 nil

错误行为

验证失败时,框架会返回第一个翻译后的验证错误,并包装为框架 result.Error

情况结果
验证成功handler 正常继续执行
一条或多条验证规则失败框架返回 bad-request 风格错误
验证过程中出现非验证类错误框架也会包装成 bad-request 风格错误

HTTP 行为:

属性
业务码result.ErrCodeBadRequest
HTTP 状态400 Bad Request

注册额外自定义规则

应用可以通过 validator.RegisterValidationRules(...) 注册自己的规则。

一个规则由 validator.ValidationRule 定义,主要字段包括:

字段作用
RuleTagvalidator 标签名
ErrMessageTemplate回退用的错误消息模板
ErrMessageI18nKeyi18n 消息 key
Validate真正的校验函数
ParseParam为错误消息占位符提取参数
CallValidationEvenIfNull是否在 null 值上也执行校验

常见模式

简单必填字段

type UserParams struct {
api.P

Username string `json:"username" validate:"required,alphanum,max=32" label:"Username"`
Email string `json:"email" validate:"omitempty,email,max=128" label:"Email"`
}

decimal 范围校验

type PriceParams struct {
api.P

Amount decimal.Decimal `json:"amount" validate:"dec_min=0,dec_max=999999.99" label:"Amount"`
}

null 包装类型校验

type UserParams struct {
api.P

Phone null.String `json:"phone" validate:"omitempty,phone_number" label:"Phone"`
}

实践建议

  • 验证规则放在 typed params / meta 结构体上,不要写进 handler
  • 尽量补 labellabel_i18n,让错误消息保持用户可读
  • 只要框架已有现成自定义规则,就优先复用
  • 自定义规则应保持窄而明确,不要做过宽的“万能校验”
  • 如果字段类型是框架 null wrapper,直接依赖内置 null 支持,不要手工拆值

下一步

继续阅读 参数与元信息,看验证是在请求解码链路中的哪个阶段触发的。