最直接的方式是使用 go-playground/validator 包配合结构体标签做参数校验,需全局初始化 validator.New() 实例,嵌套结构体用 dive,自定义规则通过 RegisterValidation 注册,HTTP 场景应手动调用 Struct 并遍历 ValidationErrors 收集全部错误。

用 validator 包配合结构体标签做参数校验最直接
Go 标准库不提供字段级校验能力,必须依赖第三方包。目前社区事实标准是 go-playground/validator,它支持嵌套、自定义规则、翻译错误信息,且与 json 标签天然协同。
安装命令:go get github.com/go-playground/validator/v10
常见错误是直接在结构体上写 validate:"required" 却忘了初始化校验器实例——validator.New() 必须调用一次,否则所有校验都静默失败。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 全局复用一个
validator.Validate实例(它并发安全),别每次校验都新建 - 结构体字段类型要和校验规则匹配,比如
int字段用min=1没问题,但string用min=1会报错(应改用min=1对应长度,或用required) - 如果字段是指针(如
*string),required不会触发非空检查,得用required_if或omitempty配合逻辑判断
嵌套结构体校验要加 validate:"dive"
当结构体字段本身是另一个结构体或切片时,校验器默认跳过其内部字段。不加 dive,哪怕子结构体字段标了 required,也不会被检查。
示例:
type Address struct {
City string `validate:"required"`
}
type User struct {
Name string `validate:"required"`
Addr Address `validate:"dive"` // 关键:必须加 dive
Tags []string `validate:"dive,required"` // 切片里每个元素都要非空
}
容易踩的坑:
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
-
dive只作用于当前字段,不会递归穿透多层;两层嵌套需写dive,dive(不推荐,应拆成中间结构体并显式标记) - 对
map[string]string用dive无效,validator不支持 map 值校验,得手动遍历 - 使用
omitempty时,dive仍会进入非零值字段,但跳过零值字段(如 nil slice、空 map)
自定义校验函数比正则更可控
内置规则覆盖大部分场景,但像“手机号格式”“密码强度”“URL 必须带 https”这类业务逻辑,硬塞进 tag 字符串里既难读又难测。这时候注册自定义函数更合适。
注册方式简单:
v := validator.New()
v.RegisterValidation("https_url", func(fl validator.FieldLevel) bool {
s := fl.Field().String()
return strings.HasPrefix(s, "https://")
})
然后在结构体中使用:URL string `validate:"https_url"`
注意点:
- 函数名(如
https_url)不能含空格或特殊符号,否则解析失败 - 校验函数接收
validator.FieldLevel,通过fl.Field()拿反射值,fl.Param()拿 tag 里传参(如len=8中的8) - 不要在自定义函数里 panic,
validator不 recover,会导致整个校验流程中断
HTTP 请求参数校验别漏掉 binding 和错误收集
在 Gin 或 Echo 等框架中,常把校验逻辑写在 handler 入口,靠 ShouldBind 自动触发。但默认行为是遇到第一个错误就返回,无法一次性返回所有字段问题。
正确做法是手动调用校验器,并收集全部错误:
if err := validate.Struct(user); err != nil {
for _, e := range err.(validator.ValidationErrors) {
// e.Field() 字段名,e.Tag() 规则名,e.Param() 参数值
log.Printf("%s failed %s: %s", e.Field(), e.Tag(), e.Param())
}
}
关键细节:
-
ShouldBind底层其实也调validate.Struct,但它只暴露第一个错误;想全量,就得绕过框架绑定,自己来 - 错误类型断言必须是
validator.ValidationErrors(slice),不是error;直接打印err.Error()可读性差,字段名和规则全混在一起 - 如果结构体字段用了
json:"name,omitempty",而请求体没传该字段,omitempty会让校验跳过——这符合预期,但容易误以为“没校验到”,其实是字段压根没解出来
真正麻烦的是跨服务调用或 CLI 场景:没有 HTTP 上下文帮你自动绑定,结构体得靠 mapstructure 或手动赋值,这时标签校验才暴露真实成本——你得确保字段名、类型、tag 三者完全对齐,稍有不一致,校验就静默失效。

















