跳至主要內容

Go Gin框架的验证器

逸尘.Lycodx大约 3 分钟后端gogin

Go Gin框架的验证器

众所周知,在 web 开发中参数校验是非常重要的一个环节,今天就来看看 gin 框架的验证器是如何使用的吧。

一、从最简单的示例开始

package main

import "github.com/gin-gonic/gin"

type UserReq struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	engine := gin.Default()

	engine.POST("user", func(ctx *gin.Context) {
		var req UserReq
		if err := ctx.ShouldBindJSON(&req); err != nil {
			fmt.Println(err)
		}
		// ... 业务逻辑
	})

	engine.Run(":8080")
}

那么我们需要如何去校验参数呢?

其实 gin 默认内置了验证器,我们只需要在结构体中加入对应的 tag 即可。

// 简单修改结构体如下
type UserReq struct {
	Name string `json:"name" binding:"required"`
	Age  int    `json:"age" binding:"required,max=200"`
}

我们传一个空参数调用该接口,查看打印结果看看吧

# 请求示例
curl -X POST http://localhost:8090/user -H "Content-Type: application/json" -d '{"name": ""}'
# 运行结果
Key: 'UserReq.Name' Error:Field validation for 'Name' failed on the 'required' tag
Key: 'UserReq.Age' Error:Field validation for 'Age' failed on the 'required' tag

可以看到已经产生了校验的效果了。

小总结: gin 默认使用 binding 这个关键字进行绑定校验的。内置了许多像:required 这样的关键字。

二、提示信息优化

虽然说已经产生了验证的效果,但是提示的内容并不符合国内用户的阅读习惯,系统大多数都是给普通用户使用的,所以需要更适合中国宝宝的提示语。

gin 的验证器已经考虑到了这一点,给我们提供了翻译工具。

go get github.com/go-playground/validator/v10
// 定义一个全局翻译器
var trans ut.Translator

// InitTrans 初始化翻译器
func InitTrans() error {
	zh := zh.New()
	uni := ut.New(zh, zh)
	trans, _ = uni.GetTranslator("zh")
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		err := zhtranslations.RegisterDefaultTranslations(v, trans)
		if err != nil {
			return err
		}
	}
	return nil
}

接口处修改为:

engine.POST("user", func(ctx *gin.Context) {
    var req UserReq
    if err := ctx.ShouldBindJSON(&req); err != nil {
        errors, ok := err.(validator.ValidationErrors)
        if ok {
            fmt.Println(errors.Translate(trans))
        } else {
            fmt.Println(err.Error())
        }
    }
    // ... 业务逻辑
})

完善代码后,此时我们再运行看看效果如何呢

map[UserReq.Age:Age为必填字段 UserReq.Name:Name为必填字段]

可以看到提示已经转化为中文了

思考: 虽然已经转化为中文了,但是效果也是不敬人意的,如何做到我们像要的结果呢?快去试试吧。

三、自定义验证规则

我们看到对于简单的 required 这样的验证已经达到了效果,但是在实际项目中可能存在很多自定义的验证规则,gin 是如何满足的呢?

直接看一个示例:

// 自定义一个手机号码的验证
v.RegisterValidation("isMobile", func(fl validator.FieldLevel) bool {
    phone := fl.Field().String()
    regex := `^1[3-9]\d{9}$`
    re := regexp.MustCompile(regex)
    return re.MatchString(phone)
})
v.RegisterTranslation("isMobile", trans, func(ut ut.Translator) error {
    return ut.Add("isMobile", `不是一个有效的`, true)
}, func(ut ut.Translator, fe validator.FieldError) string {
    t, _ := ut.T("isMobile", fe.Field())
    return t
})

这段代码写在翻译器中即可, 要使用的话就在 tag 里加入 isMobile 就行

四、参考资料

更多使用方法及技巧可以去看看官方的资料

上次编辑于: