0%

GO语言参数校验


前言

在服务器中需要接收前端发送过来的请求并且进行处理,而这些请求往往是附带参数的,所以对参数的处理是非常重要的一环

何为参数校验?

顾名思义就是对请求所附带的参数进行验证(可以理解为后端对前端所发送的数据的进一步筛选处理,然后返回对应的逻辑)

1
2
https://www.baidu.com/s?ie=UTF-8&wd=JSR303

上面这段请求中,”?”后面的内容就是参数(参数是以键值对的形式出现),还有的参数并不会出现在url当中,他们会包含在请求体当中,通过url是看不到的。

goland参数校验

常见的参数校验可以分为以下两种:

  • 客户端参数校验:在数据提交到服务器之前,发生在浏览器端或者app应用端,相比服务器端校验,用户体验更好,能实时反馈用户的输入校验结果。

  • 服务器端参数校验:发生在客户端提交数据并被服务器端程序接收之后,通常服务器端校验都是发生在将数据写入数据库之前,如果数据没通过校验,则会直接从服务器端返回错误消息,并且告诉客户端发生错误的具体位置和原因,服务器端校验不像客户端校验那样有好的用户体验,因为它直到整个表单都提交后才能返回错误信息。但是服务器端校验是应用对抗错误,恶意数据的最后防线,在这之后,数据将被持久化至数据库。当今所有的服务端框架都提供了数据校验与过滤功能(让数据更安全)。

针对服务器-go语言参数校验的三种方式:

  1. 第一种实现方式:自定义实现参数校验逻辑
    Controller层职责:从HTTP请求中获得信息,提取参数,并分发给不同的处理服务。
    重复代码是软件质量下降的重大来源

  2. 第二种实现方式:模型绑定校验–go-playground / validator–一款优秀的Go语言校验库,基于标记为结构体和单个字段实现值验证。使用简单、快捷–>结构体验证示例

    1
    go get github.com/go-playground/validator
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package main

import (
"fmt"
"github.com/go-playground/validator"
)

var validate *validator.Validate //定义

type User struct {
Name string `validate:"required"` //非空
Age uint8 `validate:"gte=0,lte=130"` // 0<=Age<=130
Email string `validate:"required,email"` //非空,email格式
//dive关键字代表 进入到嵌套结构体进行判断
Address []*Address `validate:"dive"` // 可以拥有多个地址
}
type Address struct {
Province string `validate:"required"` //非空
City string `validate:"required"` //非空
Phone string `validate:"numeric,len=11"` //数字类型,长度为11
}

func main() {
validate = validator.New() //初始化(赋值)
validateStruct() //结构体校验
validateVariable() //变量校验
}
func validateStruct() {
address := Address{
Province: "重庆",
City: "重庆",
Phone: "13366663333x",
}
user := User{
Name: "江洲",
Age: 23,
Email: "jz@163.com",
Address: []*Address{&address},
}
err := validate.Struct(user)
if err != nil {
//断言为:validator.ValidationErrors,类型为:[]FieldError
for _, e := range err.(validator.ValidationErrors) {
fmt.Println("Namespace:", e.Namespace())
fmt.Println("Field:", e.Field())
fmt.Println("StructNamespace:", e.StructNamespace())
fmt.Println("StructField:", e.StructField())
fmt.Println("Tag:", e.Tag())
fmt.Println("ActualTag:", e.ActualTag())
fmt.Println("Kind:", e.Kind())
fmt.Println("Type:", e.Type())
fmt.Println("Value:", e.Value())
fmt.Println("Param:", e.Param())
fmt.Println()
}

fmt.Println("结构体输入数据类型错误!")
return
} else {
fmt.Println("结构体校验通过")
}
}
//变量校验
func validateVariable() {
myEmail := "123@qq.com" //邮箱地址:xx@xx.com
err := validate.Var(myEmail, "required,email")
if err != nil {
fmt.Println(err)
} else {
fmt.Println("变量校验通过!")
}
}
结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
Namespace: User.Address[0].Phone
Field: phone
StructNamespace: User.Address[0].Phone
StructFiled: Phone
Tag: numeric
ActualTag: numeric
Kind: string
Type: string
Value: 13366663333x
Param:

结构体输入数据类型错误!
变量校验通过!
模型校验是通过反射机制来实现的,而反射效率相对来说效率不高(可以从ShouldBind函数从下追,把自带的校验功能屏蔽,提高框架效率???!!!)
  1. 第三种实现方式:拆解模型字段,组合结构体

参考文档

https://juejin.cn/post/7041508590913323039
https://blog.csdn.net/weixin_42117918/article/details/107407053

坚持原创技术分享,您的支持将鼓励我继续创作.