使用Go进行参数校验

spigcoder 发布于 2025-08-07 88 次阅读


在写项目的时候我们经常会遇到参数校验的问题,比如用户输入合理的email、url,或者限制用户的密码长度等等内容,在之前我自己写项目的时候,总是使用正则表达式来进行验证,但由于正则表达式相对难懂并且使用起来不方便,这里介绍其余两种参数校验的方式。

govalidator

先看一下官网的介绍:A package of validators and sanitizers for strings, structs and collections. Based on validator.js.

使用:

go get github.com/asaskevich/govalidator

然后他有一个选项需要我们去配置

func init() {
  govalidator.SetFieldsRequiredByDefault(true)
}

在上面就是如果SetFieldsRequiredByDefault设置为true,那么我们进行校验的所有结构题如果没有声明valid:“-”valid:(“email,optional”)时都会校验失败(也就是什么都没有的会失败,它相当于给每个结构体内所有字段添加了valid:"required"标签),所以我们一般会把这个选项设置为false,这样它就只会校验我们在结构题中设置需要校验的变量。

上面的valid:(“email,optional”)意思是这个值可以是指针,也就是如果为nil,会通过验证。看一下代码大家就理解了

// this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
type exampleStruct struct {
  Name  string ``
  Email string `valid:"email"`
}

// this, however, will only fail when Email is empty or an invalid email address:
type exampleStruct2 struct {
  Name  string `valid:"-"`
  Email string `valid:"email"`
}

// lastly, this will only fail when Email is an invalid email address but not when it's empty:
type exampleStruct2 struct {
  Name  string `valid:"-"`
  Email string `valid:"email,optional"`
}

然后官网有它的函数列表,感兴趣的可以去看govalidator官网

下面我们来看几个使用

println(govalidator.IsURL(`http://user@pass:domain.com/path/page`))
println(govalidator.IsType("Bob", "string"))
println(govalidator.IsType(1, "int"))
i := 1
println(govalidator.IsType(&i, "*int"))
type User    struct {
  Name string      `valid:"type(string)"`
  Age  int         `valid:"type(int)"`
  Meta interface{} `valid:"type(string)"`
}
result, err := govalidator.ValidateStruct(User{"Bob", 20, "meta"})
if err != nil {
    println("error: " + err.Error())
}
println(result)

根据这些例子,大家应该也可以理解怎么使用它来作为验证了,我看官网上还可以自己定义验证逻辑等,但因为我只是用它来做格式的认证,所以各位可以自行到官网查看

使用protovalidate

protovalidate是一种定义在proto中的一种验证方式,我们使用protobuf语法定义我们需啊的参数验证,这里来看一下语法

数字类型

// 参数必须大于 0
int64 id = 1 [(validate.rules).int64 = {gt: 0}];
// 参数必须在 0 到 120 之间
int32 age = 2 [(validate.rules).int32 = {gt:0, lte: 120}];
// 参数是 1 或 2 或 3
uint32 code = 3 [(validate.rules).uint32 = {in: [1,2,3]}];
// 参数不能是 0 或 99.99
float score = 1 [(validate.rules).float = {not_in: [0, 99.99]}];

bool类型

// 参数必须为 true
bool state = 5 [(validate.rules).bool.const = true];
// 参数必须为 false
bool state = 5 [(validate.rules).bool.const = false];

文本类型

// 参数必须为 /hello
string path = 6 [(validate.rules).string.const = "/hello"];
// 参数文本长度必须为 11
string phone = 7 [(validate.rules).string.len = 11];
// 参数文本长度不能小于 10 个字符
string explain = 8 [(validate.rules).string.min_len =  10];
// 参数文本长度不能小于 1 个字符并且不能大于 10 个字符
string name = 9 [(validate.rules).string = {min_len: 1, max_len: 10}];
// 参数文本使用正则匹配,匹配必须是非空的不区分大小写的十六进制字符串
string card = 10 [(validate.rules).string.pattern = "(?i)^[0-9a-f]+$"];
// 参数文本必须是 email 格式
string email = 11 [(validate.rules).string.email = true];

使用的时候就是

protoc --proto_path=. \
           --proto_path=./third_party \
           --go_out=paths=source_relative:. \
           --validate_out=paths=source_relative,lang=go:. \
           xxxx.proto
if err := protovalidate.Validate(req); err != nil {
        return nil, pkg.ErrorValidateConvertKratos(err)
    }