字段必须首字母大写,否则 validator 完全不校验;小写字段即使写了 binding:"required" 也会被静默跳过;嵌套结构体需加 dive,指针字段要配 omitempty;gin 默认只识别 binding 标签,不认 validate 标签。

字段必须首字母大写,否则 validator 完全不校验
validator 依赖反射读取字段值,只处理导出字段(即首字母大写)。小写字段哪怕 validate:"required" 写得再全,也会被静默跳过——不报错、不提示、不校验。
常见错误写法:type User { name string `validate:"required"` } → name 字段永远不会被检查。
正确写法:type User { Name string `json:"name" validate:"required"` }。json:"name" 控制序列化键名,和字段是否导出无关;真正起作用的是字段名 Name 本身大写。
嵌套结构体同理:内层结构体的字段也必须大写,否则子字段校验失效。
嵌套结构体要加 dive,指针字段得配 omitempty
validator 默认不会递归校验嵌套结构体字段。比如 Address Address `validate:"required"`,只会检查 Address 是否为零值,不会深入校验 Address.Street 或 Address.City。
必须显式加 dive:Address Address `validate:"required,dive"` 或 Address *Address `validate:"omitempty,dive"`。
注意:omitempty 只对指针、接口、map、slice 等类型有效;普通 struct 字段即使为空也会触发子校验。
指针字段容易踩坑:如果传了非 nil 指针(如 &Address{}),哪怕内部全是零值,dive 仍会进入子校验——此时若子字段有 required,就会失败。所以反序列化后务必确认指针状态,必要时手动置 nil。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
ShouldBind 不等于自动校验完成,Gin 默认不认 validate tag
Gin 的 c.ShouldBind(&req) 底层用的是内置 validator 实例,它只识别 binding 标签,完全忽略 validate 标签。写 validate:"email" 是无效的。
正确做法是:要么统一用 binding:"required,email",要么替换 Gin 的 validator 引擎为 go-playground/validator/v10 实例,并注册自定义规则。
常见错误现象:ShouldBind 返回 nil,但字段明显非法(如邮箱格式错)——大概率是没换 validator 实例,或字段未导出。
额外提醒:ShouldBindJSON 强制从 Body 解析 JSON;ShouldBind 则按 Content-Type 自动选解析方式(JSON/form/query),别混用。
query 和 path 参数不能直接走结构体校验,必须手动转换+校验
URL 查询参数(?page=1&size=10)和路径参数(/users/:id)是字符串,不会自动绑定到结构体字段,也不能直接调用 Validate.Struct()。
必须分三步处理:
- 用
r.URL.Query().Get("page")或chi.URLParam(r, "id")取值(别用FormValue,会触发隐式解析,干扰 multipart) - 用
strconv.ParseInt/ParseBool/time.Parse转类型,且必须检查err != nil - 再按业务逻辑校验(如
page > 0、size ),不能把空字符串当 0 处理
布尔参数尤其容易漏判:用 strconv.ParseBool,别用字符串比对 "true",否则 "1"、"on" 等非标准值会绕过校验。
最易被忽略的点是:时间字段别直接用 time.Time 接收字符串。先用 string 接,再在自定义校验函数里用 time.Parse("2006-01-02", s) 解析并校验格式,否则 datetime tag 会因格式不匹配直接报错,且错误信息难定位。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










