kratos 的 validate 插件默认不自动启用,需手动注册 middleware 或显式调用 validate();仅校验反序列化后的结构体,不处理 query/form 参数;错误需自定义处理器避免泄露细节。

validate插件默认不自动启用,必须手动注册
Kratos 的 validate 插件不会像 Gin 的 binding 那样在 HTTP handler 中自动触发校验。它只是一个独立的校验器,需要你显式调用 validate.Validate() 或集成进 middleware 才生效。
常见错误是直接给结构体加了 validate:"required" 标签,却没在 handler 里调用校验逻辑,结果请求绕过校验直接进入业务代码。
- 必须在服务初始化时注册插件:调用
app.WithMiddleware(middleware.Validate()) - 或在单个 handler 内手动校验:
if err := validate.Validate(req); err != nil { ... } - 注意:Kratos v2.5+ 的
middleware.Validate()默认只对*http.Request的 body 解析后对象生效,不处理 URL 查询参数或表单字段
结构体字段标签写法和常见陷阱
validate 使用的是 go-playground/validator/v10 规则,但 Kratos 默认只启用了基础 tag 解析(如 required、email、min),不支持自定义函数或 struct-level 校验,除非你额外配置 validator 实例。
典型错误包括:
- 写成
valid:"required"(错)→ 正确是validate:"required" - 对指针字段漏掉
omitempty导致空指针 panic:*string字段应写validate:"omitempty,required" - 嵌套结构体默认不递归校验,需显式加
validate:"dive",例如:Address *Address `validate:"dive"` -
int类型用min=1安全,但uint类型若传 0 会绕过required(因为 0 是非零值),此时应改用gt=0
HTTP 请求体校验失败时如何返回友好错误
Kratos 的 middleware.Validate() 在校验失败时默认返回 400 Bad Request 和原始 validator.FieldError 文本,可读性差。你需要替换默认错误处理器。
推荐做法是在注册 middleware 时传入自定义错误格式化函数:
middleware.Validate(
middleware.WithValidateErrorHandler(func(ctx context.Context, err error) error {
if errs, ok := err.(validator.ValidationErrors); ok {
var msgs []string
for _, e := range errs {
msgs = append(msgs, fmt.Sprintf("%s: %s", e.Field(), e.Tag()))
}
return errors.BadRequest("VALIDATION_ERROR", strings.Join(msgs, "; "))
}
return errors.BadRequest("VALIDATION_ERROR", err.Error())
}),
)
- 注意:
errors.BadRequest会触发 Kratos 的统一错误码机制,前端拿到的是标准code+message结构 - 不要直接返回
err,否则会泄露 validator 内部字段名(如FieldError.field可能暴露内部结构) - 如果用 gRPC 接口,该 middleware 同样生效,但错误会被转为
codes.InvalidArgument
query/form 参数校验需要额外解析和手动调用
validate 插件默认只校验已反序列化的结构体(比如 JSON body 绑定后的 req),对 GET /user?id=abc&name= 这类查询参数或 application/x-www-form-urlencoded 表单,Kratos 不会自动把它们映射到结构体并校验。
- 必须先用
r.FormValue("id")或r.URL.Query().Get("name")手动提取,再赋值到临时结构体 - 或使用
url.Values+mapstructure.Decode转成结构体,再调用validate.Validate() - 更稳妥的方式是统一走 JSON body,避免 query/form 分散校验逻辑
- 如果坚持用 query,建议封装一个
BindAndValidateQuery(r *http.Request, v interface{}) error工具函数,内部做ParseForm→Decode→Validate











