用validator包做结构体字段校验最直接:Go原生无参数校验机制,validator是事实标准,需通过struct tag声明规则并显式调用Validate()触发校验,返回validator.ValidationErrors需类型断言后遍历提取字段名与错误原因,不可直接返回原始error。

用 validator 包做结构体字段校验最直接
Go 原生不提供请求参数校验机制,validator(如 go-playground/validator/v10)是事实标准。它通过 struct tag 声明规则,配合 Validate() 方法触发校验,返回 error 类型的校验结果。
常见错误是只调用 Validate() 却没处理 validator.ValidationErrors 类型——它不是普通字符串错误,需类型断言后遍历提取字段名和失败原因。
- 必须为 struct 字段添加
validatetag,例如json:"username" validate:"required,min=3,max=20" - 接收 HTTP 请求时,先
json.Unmarshal到结构体,再立即调用validate.Struct() - 不要在 handler 里写一堆
if len(x) == 0手动判断,既重复又难维护 - 注意
omitempty和validate的组合:空字符串可能被忽略,但required仍会报错,需按业务决定是否加omitempty
把 validator.FieldError 转成可读提示要自己映射
validator 默认返回的错误信息是英文、带字段路径和约束名(如 Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag),前端或 API 消费者无法直接使用。
必须手动遍历 validator.ValidationErrors,对每个 validator.FieldError 提取 Field()、Tag()、Value(),再查表映射成中文提示。别依赖第三方翻译包,容易失控且多一层依赖。
- 建议建一个 map[string]string 映射常用 tag:比如
"required": "%s 不能为空","email": "%s 格式不正确" - 占位符用
%s拼接Field()返回的字段名(如"Email"),避免硬编码字段名 - 如果字段名是
jsonkey(如"user_name"),可在 struct tag 里加label:"用户名",校验时优先取 label - 注意
Value()可能是 nil 或未导出字段,打印前先判断类型和有效性
嵌套结构体和 slice 校验容易漏掉递归验证
当请求体含嵌套对象(如 User{Profile: Profile{Age: -1}})或数组(如 Tags []string)时,validate.Struct() 默认不会自动深入校验子字段或元素,除非显式启用。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
常见现象是外层结构体校验通过,但内层字段明显非法却没报错——因为没开 ValidateNested 或没给 slice 元素加 tag。
- 启用嵌套校验:用
validate.Struct(myStruct, validator.WithRequiredStructEnabled())或初始化 validator 实例时设Options(validator.WithRequiredStructEnabled()) - slice 元素校验必须加
divetag,例如Tags []string `validate:"dive,required,min=1,max=50"` - 嵌套 struct 字段需同时有
validatetag 和非零值(或required),否则dive不生效 - 避免无限递归:若结构体含自引用(如树形节点),需手动控制深度或跳过特定字段
HTTP handler 中统一拦截校验错误并返回 JSON
每个 handler 都写一遍 if err != nil { ... } 太冗余。应该抽成中间件或封装一个 BindAndValidate 函数,在解析后立刻校验,并统一构造 400 Bad Request 响应。
别把校验逻辑塞进 controller 层,也别让 model 层承担 HTTP 错误构造职责——校验是请求入口的事,错误响应格式属于 transport 层约定。
- 函数签名建议为
func BindAndValidate(r *http.Request, dst interface{}) error,内部完成json.NewDecoder+Validate+ 错误转提示 - 响应体结构固定:例如
{"code": 400, "message": "请求参数错误", "details": [{"field": "email", "reason": "格式不正确"}]} - 不要用
http.Error直接返回文本,确保 content-type 是application/json,否则前端解析失败 - 日志里记录原始
ValidationErrors(非映射后提示),方便排查规则配置问题
字段名大小写、嵌套层级、错误码定义这些细节,比选哪个校验库更重要。校验逻辑一旦分散在多个地方,改一个规则就要翻五六处代码。

















