Go接口参数校验应使用github.com/go-playground/validator/v10,它是事实标准库,支持结构体字段标签校验、嵌套、自定义规则及错误翻译,性能好且不依赖HTTP框架;需注意字段导出、标签规范、Gin中正确替换默认validator实例、分来源定义校验struct、time.Time格式严格匹配等关键实践。
validator 是事实标准生产项目中,validator(即 github.com/go-playground/validator/v10)是 Go 里最成熟、最常被选用的结构体字段校验库。它不依赖 HTTP 框架,能直接作用于 struct 字段标签,支持嵌套、自定义规则、翻译错误信息,且性能足够好。别用 reflect 手写校验逻辑——重复造轮子、易漏边界、难维护。
常见错误现象:binding:"required" 写成 binding:"required,true"(后者是 Gin 的旧语法,validator 不认);或把 json:"user_id" 和 validate:"required" 放在不同字段上导致漏校验。
Validate.Struct(),不要对每个字段单独调用 Validate.Field()
validator 无法反射访问omitempty 和校验逻辑的关系:空字符串、零值字段若带 omitempty,可能跳过校验——这不是 bug,是设计使然,需按业务决定是否加 required
validator 并覆盖默认行为Gin 默认用的是 go-playground/validator v9,但 v10 更稳定、文档更全。要替换,必须手动注册新实例,并重写 engine.Validator。否则你写的 validate:"email,lt=256" 可能静默失效。
关键步骤:
validator.Validate 实例,调用 RegisterValidation 注册自定义规则(如手机号、身份证)router.Use(func(c *gin.Context) { c.Next() }) 不起作用;必须写 engine.Validator = &defaultValidator{validator: v}
c.JSON(400, err)——err 是 validator.ValidationErrors 类型,需用 err.Translate(trans) 转成可读提示示例片段:
v := validator.New()
v.RegisterValidation("chinese_mobile", validateChineseMobile)
uni := ut.New(en.New(), en.New())
trans, _ := uni.GetTranslator("en")
engine.Validator = &defaultValidator{validator: v, trans: trans}
同一接口常同时接收 query、json、form 多种输入,但 validator 本身不区分来源——它只校验 struct。难点在于「怎么把不同来源的数据正确绑定到同一个 struct 字段」。
正确做法是:为每种输入定义独立 struct,用标签明确指定来源,再分别校验。不要试图用一个 struct + 多个 binding 标签混用(比如同时写 json:"name" form:"name" query:"name"),Gin 会以最后解析的为准,极易出错。
GET /users?name=foo&age=25 → 定义 type UserQuery struct { Name string `form:"name" validate:"required"` },用 c.ShouldBindQuery(&q)
POST /users JSON body → type UserBody struct { Email string `json:"email" validate:"required,email"` },用 c.ShouldBindJ
SON(&b)
ShouldBindXXX 会自动 abort,但错误信息是英文 raw 字符串,需自己包装成统一格式返回time.Time 字段校验总失败?时间格式和标签要严格匹配time.Time 是 Go 接口校验里最常翻车的类型。不是 validator 不支持,而是你没告诉它「这个字符串按什么 layout 解析」。默认只认 RFC3339(如 "2006-01-02T15:04:05Z"),而前端传的往往是 "2006-01-02" 或 "2006-01-02 15:04:05"。
解决方法只有两个:
time_format 标签:CreatedAt time.Time `json:"created_at" time_format:"2006-01-02 15:04:05" validate:"required"`
string 接收,校验后再 parse:CreatedAtStr string `json:"created_at" validate:"required,datetime=2006-01-02 15:04:05"`,避免 time.Time 零值干扰校验逻辑注意:datetime 是 validator v10 内置验证器,但必须和 time_format 标签值完全一致,多一个空格都报 Key: 'xxx.CreatedAt' Error:Field validation for 'CreatedAt' failed on the 'datetime' tag。
真正麻烦的从来不是“有没有校验”,而是“校验失败后,错误信息能不能准确定位到字段、能不能被前端直接展示、会不会因时区或格式差异让测试同学反复问‘我传的明明是对的’”。这些细节,比选哪个库重要得多。