您的位置 首页 golang

参数校验错误信息中文处理

在上一节我们介绍到,gin可以使用ShouldBind方法把参数绑定到结构体,但是没有介绍到参数校验的方式,这节我们来介绍参数校验和校验失败后转换成中文返回前端。

1.数据校验

下面我们开始一个简单的例子:

  1. 在根目录的requests目录下新建一个test_request.go
package requests//测试请求结构体 该结构体定义了请求的参数和校验规则type TestRequest struct {    Username string `form:"username" binding:"required"`}
  1. 在根目录的api目录下新建一个test.go的控制器,定义test控制器
package apiimport (    "cn.sockstack/gin_demo/requests"    "github.com/gin-gonic/gin"    "net/http")func Test(c *gin.Context)  {    //实例化一个TestRequest结构体,用于接收参数    testStruct := requests.TestRequest{}    //接收请求参数    err := c.ShouldBind(&testStruct)    //判断参数校验是否通过,如果不通过,把错误返回给前端    if err != nil {        c.JSON(http.StatusOK, gin.H{"error": err.Error()})        return    }    //校验通过,返回请求参数    c.JSON(http.StatusOK, gin.H{"params": testStruct})}
  1. 在根目录的routers下定义/test路由,分别新建init.go和test.go文件初始化路由.

test.go

package routersimport (    "cn.sockstack/gin_demo/api"    "github.com/gin-gonic/gin")func test(r *gin.Engine)  {    //定义/test路由    r.GET("/test", api.Test)}

init.go

package routersimport "github.com/gin-gonic/gin"func Init(r *gin.Engine)  {    //注册test路由    test(r)}
  1. 在main.go中注册路由
package main// 导入gin包import (    "cn.sockstack/gin_demo/pkg/config"    "cn.sockstack/gin_demo/routers"    "fmt"    "github.com/gin-gonic/gin")// 入口函数func main() {    // 初始化一个http服务对象    r := gin.Default()    //注册路由    routers.Init(r)    r.Run(fmt.Sprintf("%s:%d", config.Server.Address, config.Server.Port)) // 监听并在 0.0.0.0:8081 上启动服务}
  1. 运行并访问localhost:8081/test,不带参数会报错
{    "error": "Key: 'TestRequest.Username' Error:Field validation for 'Username' failed on the 'required' tag"}
  1. 运行并访问localhost:8081/test?username=sockstack,则返回响应的参数。
{    "params": {        "Username": "sockstack"    }}

上面的例子已经可以实现参数校验和接收参数了,但是校验不通过的时候返回的提示是英文的,下面我们介绍一下怎么把错误转成中文返回。

2.校验参数失败提示自动翻译

通过查看代码我们发现gin默认的校验器使用的是validator包,并且查看文档发现validator是可以把英文错误翻译成中文的。

package mainimport (    "fmt"    "github.com/go-playground/locales/en"    ut "github.com/go-playground/universal-translator"    "github.com/go-playground/validator/v10"    en_translations "github.com/go-playground/validator/v10/translations/en")// User contains user informationtype User struct {    FirstName      string     `validate:"required"`    LastName       string     `validate:"required"`    Age            uint8      `validate:"gte=0,lte=130"`    Email          string     `validate:"required,email"`    FavouriteColor string     `validate:"iscolor"`                // alias for 'hexcolor|rgb|rgba|hsl|hsla'    Addresses      []*Address `validate:"required,dive,required"` // a person can have a home and cottage...}// Address houses a users address informationtype Address struct {    Street string `validate:"required"`    City   string `validate:"required"`    Planet string `validate:"required"`    Phone  string `validate:"required"`}// use a single instance , it caches struct infovar (    uni      *ut.UniversalTranslator    validate *validator.Validate)func main() {    // NOTE: ommitting allot of error checking for brevity    en := en.New()    uni = ut.New(en, en)    // this is usually know or extracted from http 'Accept-Language' header    // also see uni.FindTranslator(...)    trans, _ := uni.GetTranslator("en")    validate = validator.New()    en_translations.RegisterDefaultTranslations(validate, trans)    translateAll(trans)    translateIndividual(trans)    translateOverride(trans) // yep you can specify your own in whatever locale you want!}func translateAll(trans ut.Translator) {    type User struct {        Username string `validate:"required"`        Tagline  string `validate:"required,lt=10"`        Tagline2 string `validate:"required,gt=1"`    }    user := User{        Username: "Joeybloggs",        Tagline:  "This tagline is way too long.",        Tagline2: "1",    }    err := validate.Struct(user)    if err != nil {        // translate all error at once        errs := err.(validator.ValidationErrors)        // returns a map with key = namespace & value = translated error        // NOTICE: 2 errors are returned and you'll see something surprising        // translations are i18n aware!!!!        // eg. '10 characters' vs '1 character'        fmt.Println(errs.Translate(trans))    }}func translateIndividual(trans ut.Translator) {    type User struct {        Username string `validate:"required"`    }    var user User    err := validate.Struct(user)    if err != nil {        errs := err.(validator.ValidationErrors)        for _, e := range errs {            // can translate each error one at a time.            fmt.Println(e.Translate(trans))        }    }}func translateOverride(trans ut.Translator) {    validate.RegisterTranslation("required", trans, func(ut ut.Translator) error {        return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details    }, func(ut ut.Translator, fe validator.FieldError) string {        t, _ := ut.T("required", fe.Field())        return t    })    type User struct {        Username string `validate:"required"`    }    var user User    err := validate.Struct(user)    if err != nil {        errs := err.(validator.ValidationErrors)        for _, e := range errs {            // can translate each error one at a time.            fmt.Println(e.Translate(trans))        }    }}

那么我们改造gin的校验提示。

  1. 在requests目录下新建init.go文件
package requestsimport (   "github.com/gin-gonic/gin/binding"   "github.com/go-playground/locales/zh"   ut "github.com/go-playground/universal-translator"   "github.com/go-playground/validator/v10"   zh_translations "github.com/go-playground/validator/v10/translations/zh")var (   uni      *ut.UniversalTranslator   validate *validator.Validate   trans ut.Translator)func init() {   //注册翻译器   zh := zh.New()   uni = ut.New(zh, zh)   trans, _ = uni.GetTranslator("zh")      //获取gin的校验器   validate := binding.Validator.Engine().(*validator.Validate)   //注册翻译器   zh_translations.RegisterDefaultTranslations(validate, trans)}//Translate 翻译错误信息func Translate(err error) map[string][]string {   var result = make(map[string][]string)   errors := err.(validator.ValidationErrors)   for _, err := range errors{      result[err.Field()] = append(result[err.Field()], err.Translate(trans))   }   return result}
  1. 修改控制器
package apiimport (    "cn.sockstack/gin_demo/requests"    "github.com/gin-gonic/gin"    "net/http")func Test(c *gin.Context)  {    //实例化一个TestRequest结构体,用于接收参数    testStruct := requests.TestRequest{}    //接收请求参数    err := c.ShouldBind(&testStruct)    //判断参数校验是否通过,如果不通过,把错误返回给前端    if err != nil {        c.JSON(http.StatusOK, gin.H{"error": requests.Translate(err)})        return    }    //校验通过,返回请求参数    c.JSON(http.StatusOK, gin.H{"params": testStruct})}
  1. 运行并访问localhost:8081/test,不带参数会报错,但是报错信息已经翻译成中文了
{    "error": {        "Username": [            "Username为必填字段"        ]    }}

出处gin从入门到实践更多精彩文章,请关注我的博客SOCKSTACK,分享我的工作经验。


文章来源:智云一二三科技

文章标题:参数校验错误信息中文处理

文章地址:https://www.zhihuclub.com/5911.shtml

关于作者: 智云科技

热门文章

网站地图