输入校验(为什么在微信里面打了一堆空格,键盘上的 “发送” 变成了 “换行”,右边也没有独立发送按钮 想点发送,发现按钮是灰的或者直接消失了)

0 阅读4分钟

为什么在微信里面打了一堆空格,键盘上的 “发送” 变成了 “换行”,右边也没有独立发送按钮 想点发送,发现按钮是灰的或者直接消失了: 为什么你打了空格,发送按钮直接没了?

这就是微信前端输入校验的典型表现: 当你输入框里只有空格(或其他不可见空白字符)时,微信会判定为「无有效内容」,直接隐藏发送按钮,根本不让你提交

Go 语言输入校验(Validation)详解

在实际开发中,用户提交的数据是不可信的。

例如:

{
    "username":"admin",
    "password":"123"
}

如果后端不校验:

  • 用户名为空
  • 密码长度不足
  • 邮箱格式错误
  • 年龄为负数

都会直接进入数据库;

因此:

输入校验(Validation)

是后端开发必须要做的事情


一、什么是输入校验

例如注册接口:

{
    "username":"zhangsan",
    "password":"123456",
    "email":"123@qq.com"
}

后端需要检查:

username 是否为空

password 长度是否符合要求

email 格式是否正确

年龄是否超出范围

这个过程就叫:

输入校验
(Input Validation)

二、Gin中的输入校验

Gin已经帮我们集成好了:

github.com/go-playground/validator/v10

所以:

c.ShouldBindJSON()

不仅能绑定数据:

{
    "username":"admin"
}

还能自动校验


三、最简单的例子

定义结构体:

type RegisterReq struct {
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

接口:

func Register(c *gin.Context) {

    var req RegisterReq

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(400, gin.H{
            "msg": err.Error(),
        })
        return
    }

    c.JSON(200, gin.H{
        "msg": "success",
    })
}

请求:

{
    "username":"admin"
}

少了 password

返回:

{
    "msg":"Key: 'RegisterReq.Password' Error:Field validation for 'Password' failed on the 'required' tag"
}

说明:

required

表示不能为空

四、常用校验标签


required

不能为空

type User struct {
    Name string `json:"name" binding:"required"`
}

min

最小长度

type User struct {
    Password string `json:"password" binding:"min=6"`
}

要求:

长度至少6位

max

最大长度

type User struct {
    Username string `json:"username" binding:"max=20"`
}

要求:

最多20个字符

len

固定长度

type User struct {
    Code string `json:"code" binding:"len=6"`
}

要求:

必须6位

验证码经常用。


五、数字校验


gt

大于

Age int `json:"age" binding:"gt=0"`

要求:

age > 0

gte

大于等于

Age int `json:"age" binding:"gte=18"`

要求:

age >= 18

lt

小于

Age int `json:"age" binding:"lt=100"`

要求:

age < 100

lte

小于等于

Age int `json:"age" binding:"lte=100"`

要求:

age <= 100

六、邮箱校验

type User struct {
    Email string `json:"email" binding:"required,email"`
}

请求:

{
    "email":"123@qq.com"
}

通过


请求:

{
    "email":"abc"
}

失败


七、手机号校验

validator没有内置中国手机号规则。

一般自己写:

type User struct {
    Phone string `json:"phone" binding:"required,len=11"`
}

或者:

regexp

校验。


八、多个规则同时使用

type User struct {
    Username string `json:"username" binding:"required,min=3,max=20"`
}

含义:

不能为空

至少3位

最多20位

九、ShouldBindJSON干了什么

很多人只会写:

c.ShouldBindJSON(&req)

不知道发生了什么

实际上:


第一步

读取Body

{
    "username":"admin",
    "password":"123456"
}

第二步

根据:

json:"username"

映射字段

变成:

req.Username = "admin"

第三步

检查:

binding:"required"

第四步

检查:

binding:"min=6"

第五步

全部通过返回:

err == nil

最终:

JSON
 ↓
结构体
 ↓
binding校验
 ↓
成功

十、自定义校验

例如:

用户名必须以 admin 开头

Gin默认没有。

可以注册自己的规则。

validate.RegisterValidation("admin", func(fl validator.FieldLevel) bool {

    value := fl.Field().String()

    return strings.HasPrefix(value, "admin")
})

使用:

type User struct {
    Username string `binding:"admin"`
}

十一、项目中最常见写法

type LoginReq struct {
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required,min=6,max=20"`
}
func Login(c *gin.Context) {

    var req LoginReq

    if err := c.ShouldBindJSON(&req); err != nil {

        c.JSON(400, gin.H{
            "msg": err.Error(),
        })

        return
    }

    // 登录逻辑

}

十二、面试高频问题

Q1:Gin如何进行参数校验?

答:

Gin底层集成了 validator 库。

通过 binding 标签定义校验规则。

调用 ShouldBindJSON 时:

先绑定JSON到结构体

再自动执行校验

Q2:required是什么意思?

binding:"required"

表示:

字段不能为空

Q3:ShouldBindJSON做了什么?

读取请求Body

JSON转结构体

执行binding规则校验

返回error

总结

ShouldBindJSON
=
JSON解析
+
结构体赋值
+
validator校验

常见标签:

required 必填 min 最小长度 max 最大长度 len 固定长度 gt 大于 gte 大于等于 lt 小于 lte 小于等于 email 邮箱格式

实际开发中最常用的组合:

binding:"required" binding:"required,min=6,max=20" binding:"required,email"