在C/S架构下,服务端在校验请求参数时,若出现参数错误,要响应给客户端一个错误消息,通常我们会统一响应“参数错误”。
但是,如果只是一味的提示参数错误,我并不知道具体是哪个参数错了呀!能不能有更详细,更细致的提示信息?例如(账号错误、密码为空、姓名不能包含数字),当然可以,下面我来教你如何利用validator包实现自定义参数错误信息。
validator包下载
validator是开源的第三方包,专门用于进行参数校验。我们先下载一下:
github.com/go-playground/validator/v10
打上结构体标签
validator包提供了结构体标签选项,我们可以为想要进行参数校验的字段打上标签,之后就会以此标签作为校验标准。
进行参数校验
Struct方法会检验其参数s(假设参数s为结构体)是否符合结构体标签的标准(上文提到的validate标签)。若不符合标准,则将具体不符合的情况作为err返回。
现在我们模拟一遍请求参数错误时的场景
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type RegisterModel struct {
Username string `validate:"required,numeric"` // numeric 必须是数字
Password string `validate:"required,alphanum"` // alphanum 必须是数字字母组合
Name string `validate:"required"` // required 必须非空
Age int `validate:"required,gte=0,lte=100,numeric"` // gte, lte 为最大最小值
Gender string `validate:"required,oneof=男 女"` // oneof 必须为其中的某个值
}
func main() {
// 模拟客户端发来的请求参数
model := RegisterModel{
Username: "中文中文", // 故意让其不符合标准
Password: "123哈哈哈",
Name: "",
}
// 用validator包进行校验
validate := validator.New() // 先new一个对象
err := validate.Struct(model) // 通过对象调用Struct方法
if err != nil {
fmt.Println(err)
}
}
打印错误信息,可以发现其中包含了 不符合标准的字段 和 不符合标准的标签(下文将其统称为错误字段、错误标签)
有了这些信息,就方便我们进行自定义参数信息了!但是仅有这些还不够,我们需要将这些信息各自提取到变量中。
将错误字段和错误标签提取出来
validator包里也给我们提供了方法:我们先将得到的err断言成validator.ValidationErrors,其本质是一个结构体切片,结构体中包含了错误字段和错误标签。接着我们遍历该结构体,即可拿到错误字段和错误标签。
// 将err中包含的字段和标签提取出来
if validationErrors, ok := err.(validator.ValidationErrors); ok { // 将err断言
for _, vErr := range validationErrors { // validationErrors 是一个结构体切片
fmt.Println(vErr.StructField(), vErr.Tag()) // 打印得到的错误字段和错误标签
}
}
实战如下
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type RegisterModel struct {
Username string `validate:"required,numeric"` // numeric 必须是数字
Password string `validate:"required,alphanum"` // alphanum 必须是数字字母组合
Name string `validate:"required"` // required 必须非空
Age int `validate:"required,gte=0,lte=100,numeric"` // gte, lte 为最大最小值
Gender string `validate:"required,oneof=男 女"` // oneof 必须为其中的某个值
}
func main() {
// 模拟客户端发来的请求参数
model := RegisterModel{
Username: "中文中文",
Password: "123哈哈哈",
Name: "",
}
// 用validator包进行校验
validate := validator.New()
err := validate.Struct(model)
if err != nil {
fmt.Println(err)
// 将err中包含的字段和标签提取出来
if validationErrors, ok := err.(validator.ValidationErrors); ok {
for _, vErr := range validationErrors { // validationErrors 是一个结构体切片
vErr.StructField()
vErr.Tag()
fmt.Println(vErr.StructField(), vErr.Tag())
}
}
}
}
现在我们有了错误字段和错误标签,我们就可以自定义参数错误信息了。
自定义参数错误信息
这里我用的方法是我自创的,比较土,主要是在map中通过错误字段、错误标签映射到自定义的信息。
首先声明两个map
然后在遍历中通过map的映射关系获取到自定义信息。
实战:
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type RegisterModel struct {
Username string `validate:"required,numeric"` // numeric 必须是数字
Password string `validate:"required,alphanum"` // alphanum 必须是数字字母组合
Name string `validate:"required"` // required 必须非空
Age int `validate:"required,gte=0,lte=100,numeric"` // gte, lte 为最大最小值
Gender string `validate:"required,oneof=男 女"` // oneof 必须为其中的某个值
}
// 错误标签map
var tagMsg = map[string]string{
"no-whitespace": "不能含有空格", // 键为结构体标签,值为自定义的错误信息
"required": "不能为空",
"numeric": "必须是数字",
"alphanum": "只能包含字母和数字",
"oneof": "错误",
"lte": "超出限定范围",
"gte": "超出限定范围",
}
// 错误字段map
var fieldMsg = map[string]string{
"Username": "账号", // 键为字段名,值为自定义的字段名信息
"Password": "密码",
"Name": "姓名",
"Age": "年龄",
"Gender": "性别",
"Permission": "权限",
}
func main() {
// 模拟客户端发来的请求参数
model := RegisterModel{
Username: "中文中文",
Password: "123哈哈哈",
Name: "",
}
// 用validator包进行校验
validate := validator.New()
err := validate.Struct(model)
if err != nil {
fmt.Println(err)
// 将err中包含的字段和标签提取出来
if validationErrors, ok := err.(validator.ValidationErrors); ok {
for _, vErr := range validationErrors { // validationErrors 是一个结构体切片
fmt.Println(fieldMsg[vErr.StructField()] + tagMsg[vErr.Tag()])
}
}
}
}
输出结果:
至此,我们就用validator包实现自定义参数错误信息。
感谢浏览,如有不对欢迎指出。