使用go-playground/validator实现请求参数验证并输出中文错误信息

时间:2021-11-12     作者:smarteng     分类: Go语言


实现目标

go-playground/validator 原始的参数验证错误信息为英文字符串,很不友好。
在网上找到了这篇文章,解决了大部分问题。但是返回的错误信息没有分字段,且没有真实字段名,对前端来说不友好。
最后自己动手稍作改造,先看看最后实现的结果:
请求数据类型:

//PageInfo 分页请求数据结构
type PageInfo struct {
    Page     int `json:"page"  validate:"required,min=1" label:"页码"`
    PageSize int `json:"pageSize" validate:"required,max=100" label:"每页大小"`
}

错误请求参数响应 json 如下:

{
    "code": -1,
    "msg": "请求参数验证失败",
    "errors": {
        "Page": "页码为必填字段",
        "PageSize": "每页大小为必填字段"
    }
}

安装扩展包

github.com/go-playground/locales
github.com/go-playground/universal-translator
github.com/go-playground/validator/v10

添加 validator 服务包

validator.go

package validator

import (
    "os"
    "reflect"
    "fmt"

    "github.com/go-playground/locales/zh"
    translator "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zh_translations "github.com/go-playground/validator/v10/translations/zh"
)

//Validate 验证器
var Validate *validator.Validate
var trans translator.Translator

func init() {
    uni := translator.New(zh.New())
    trans, _ = uni.GetTranslator("zh")
    Validate = validator.New()
    //注册一个函数,获取struct tag里自定义的label作为字段名--重点1
    Validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
        label := fld.Tag.Get("label")
        if label == "" {
            return fld.Name
        }
        return label
    })
    //注册翻译器
    err := zh_translations.RegisterDefaultTranslations(Validate, trans)
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(0) //无法初始化验证器,退出应用
    }
}

//Translate 翻译工具
func Translate(err error, s interface{}) map[string]string {
    r := make(map[string]string)
    t := reflect.TypeOf(s).Elem()
    for _, err := range err.(validator.ValidationErrors) {
                //使用反射方法获取struct种的json标签作为key --重点2
        var k string
        if field, ok := t.FieldByName(err.StructField()); ok {
            k = field.Tag.Get("json")
        }
        if k == "" {
            k = err.StructField()
        }
        r[k] = err.Translate(trans)
    }
    return r
}

使用方法

//PageInfo 分页请求数据结构
type PageInfo struct {
    Page     int `json:"page"  validate:"required,min=1" label:"页码"`
    PageSize int `json:"pageSize" validate:"required,max=100" label:"每页大小"`
}

//Errors 错误响应
type Errors struct {
    Code   int         `json:"code"`
    Msg    string      `json:"msg"`
    Errors interface{} `json:"errors"`
}

…………
func Hello(c *gin.Context) {
    var pageInfo PageInfo 
    _ = c.ShouldBind(&pageInfo) //这里是gin的绑定参数方法,请改成自己的
    err := validator.Validate.Struct(pageInfo) //注意导入validator包
    if err != nil {
        r := validator.Translate(err,pageInfo)
        c.JSON(http.StatusBadRequest, Errors{
              Code:   -1,
              Msg:    "请求参数验证失败",
              Errors: r,
            })
        return
    }
    …………
}
标签: validator