Gin框架入门系列【7】参数校验

1,256 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

简单参数校验

在web程序开发中,参数校验是必不可少的,通过参数校验可以保证请求参数的合法性并且识别恶意请求,参数校验的方法有很多,最简单的方法就是后端接收到参数之后使用if进行判断,当参数不合法时返回异常提示信息,例如在注册页面,需要保证两次输入的密码是否一致等。

这种参数校验是最简单直接的,同时也是最繁琐最破坏代码的,毕竟谁也不想在写逻辑之前还要写大串大串的if来校验参数。

validator

在使用validator库之前需要先导入:

go get github.com/go-playground/validator/v10

validator文档:pkg.go.dev/github.com/…

在Gin框架中可以使用validator库来进行参数校验,使用这个库进行校验时,可以避免大串的if,只需要在定义结构体时在binding标签中指定参数的合法范围即可。

代码示例:

type Register struct {
  Username   string `json:"username" binding:"required"`
  Password   string `json:"password" binding:"required"`
  RePassword string `json:"re_password" binding:"required,eqfield=Password"`
  Email      string `json:"email" binding:"required,email"`
  Age        int    `json:"age" binding:"gt=18,lt=60"`
}

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

  g.POST("/register", func(c *gin.Context) {
    var register Register
    err := c.BindJSON(&register)
    if err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
        "error": err.Error(),
      })
      return
    }
    c.JSON(http.StatusOK, gin.H{
      "message": "OK",
    })
  })

  err := g.Run(":8888")
  if err != nil {
    return
  }
}

上面代码中模拟了一个注册请求,并且针对所有参数指定了binding标签,标签中的required表示当前参数为必填,如果在请求时没有携带该参数则会报错,email表示该参数格式必须为邮箱格式,gt表示大于,lt表示小于,上面代码中的age参数必须大于18小于60,eqfield=Password表示当前字段的值必须和Password字段的值相同。

可以使用postman或者浏览器直接发送请求进行验证。

常用参数约束如下:

约束说明示例
required必填required
email格式必须是邮箱格式email
eqfield指定与某个字段值一样eqfield=Password
ne不等于ne=5
gt大于gt=18
gte大于等于gte=18
lt小于lt=60
lte小于等于lte=60
max最大max=60
min最小min=18
oneof只能是指定值中的一个oneof=male female
eq等于eq=test
len长度len=20
startswith字符串以什么开头startswith=hello
endswith字符串以什么结尾endswith=world
contains字符串包含子串contains=test

自定义参数校验

上面介绍了Validator中的简单参数校验和常用的约束,但是在开发中,还可能会碰到比较复杂的参数校验,这些情况下使用上述提供的功能就无法完成,就需要我们自己自定义参数校验了,自定义参数校验的方法很简单,具体代码如下:

type Register struct {
  Username   string `json:"username" binding:"required" validate:"userName"`
  Password   string `json:"password" binding:"required"`
  RePassword string `json:"re_password" binding:"required,eqfield=Password"`
  Email      string `json:"email" binding:"required,email"`
  Age        int    `json:"age" binding:"gt=18,lt=60"`
}

// 自定义校验函数
func userName(fl validator.FieldLevel) bool {
  if fl.Field().String() != "testName" {
    return false
  }
  return true
}

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

  // 新建一个validator
  validate := validator.New()

  g.POST("/register", func(c *gin.Context) {
    var register Register
    // 将自定义的tag和校验函数注册到validator中,并将两者绑定
    err := validate.RegisterValidation("userName", userName)
    err = c.BindJSON(&register)
    // 参数校验
    err = validate.Struct(register)
    if err != nil {
      c.JSON(http.StatusBadRequest, gin.H{
        "error": err.Error(),
      })
      return
    }
    c.JSON(http.StatusOK, gin.H{
      "message": "OK",
    })
  })

  err := g.Run(":8888")
  if err != nil {
    return
  }
}

自定义参数校验需要使用到validate标签,并且在标签内自定义一个约束名称,然后需要自定义一个参数校验函数,函数参数为validator.FieldLevel,通过该参数可以拿到自定义约束字段的值,然后根据是否校验通过返回true或false。

代码中通过validate := validator.New()新建一个validator,然后调用RegisterValidation将自定义校验注册到validator中,传入自定义约束名称和自定义校验函数,完成两者的绑定,最后在代码中调用Struct方法即可完成参数校验。