必须导出字段(首字母大写)且避免nil结构体;query与json需分结构体;时间字段用string+datetime格式校验;自定义规则须在gin.default()后注册到binding.validator.engine()。

字段没校验?先看首字母和 nil 指针
validator 对小写字母开头的字段(如 name string)完全无视,不报错也不跳过——它根本读不到。结构体传入 Validate.Struct() 时若为 nil,直接 panic。这不是配置问题,是反射机制限制。
- 所有需校验字段必须导出:写成
Name string,不是name string - 嵌套字段如
Address Address默认递归校验;但若写成Address *Address且值为nil,内层直接跳过(设计如此,非 bug) - 校验前加空值判断:
if req == nil { return errors.New("request is nil") } - 用
reflect.TypeOf(u).NumField()快速确认字段是否被反射识别
query 和 JSON 必须分结构体,混用等于自废武功
BindQuery 和 BindJSON 解析逻辑完全不同:前者对 limit=abc 会静默设为 0,后者直接 decode 失败返回 400。混用同一结构体会让校验时机错乱、错误提示模糊。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 为 URL 查询参数单独建结构体,例如
UserListQuery,手动用strconv.ParseInt(r.URL.Query().Get("page"), 10, 64)转换并检查err - JSON Body 走标准
BindJSON+validate标签,别指望binding:"time_format"可靠——它可能用本地时区或掩盖格式错误 - 时间字段别写
At time.Time `validate:"datetime"`,datetime只对string生效;应声明为At string `validate:"datetime=2006-01-02T15:04:05Z"`,校验后再调time.Parse(time.RFC3339, req.At)
自定义规则不触发?注册时机和签名全错了
写了 validate:"chinese_mobile" 却没反应,大概率是规则名压根没注册进 validator 实例,或者函数签名不对。Gin 内部持有的 validator 实例和你自己 validator.New() 创建的是两个对象。
- 注册必须在
gin.Default()之后、任何路由注册之前:binding.Validator.Engine().(*validator.Validate).RegisterValidation("chinese_mobile", fn) - 函数签名必须严格为
func(fl validator.FieldLevel) bool,返回true表示通过,false表示失败 -
fl.Field().Interface()返回interface{},取值必须手动断言,例如fl.Field().Interface().(string),否则 panic - 规则名大小写敏感,不能含空格或特殊符号;tag 中不能带参数,如
validate:"chinese_mobile(11)"是非法语法
required 不拦 0、空格、空切片?这是零值语义,不是业务“非空”
required 只判断 Go 零值:int 的零值是 0,time.Time 是 0001-01-01,[]string 是 [],string 是 ""。用户提交的 " "、"\u200b" 全部放过。
- 业务中
0非法?改用gt=0或ne=0 - 字符串要 trim 后非空?绑定前统一调
strings.TrimSpace(),或注册isNotBlank规则 - 数组要求非空?用
min=1,不是required;子项校验加dive,如Tags []string `validate:"min=1,dive,required"` - 跨字段逻辑(如 “status=active 时 email 必填”)不能靠
eqfield,得用StructLevel注册函数,或拆成多个校验步骤
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










