发布时间:2023-11-02 12:30
上篇介绍了go-grpc-middleware的grpc_zap、grpc_auth和grpc_recovery使用,本篇将介绍grpc_validator,它可以对gRPC数据的输入和输出进行验证。
这里使用第三方插件go-proto-validators自动生成验证规则。
go get github.com/mwitkow/go-proto-validators
1.新建simple.proto文件
syntax = \"proto3\"; package proto; import \"github.com/mwitkow/go-proto-validators/validator.proto\"; message InnerMessage { // some_integer can only be in range (1, 100). int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}]; // some_float can only be in range (0;1). double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}]; } message OuterMessage { // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). string important_string = 1 [(validator.field) = {regex: \"^[a-z]{2,5}$\"}]; // proto3 doesn\'t have `required`, the `msg_exist` enforces presence of InnerMessage. InnerMessage inner = 2 [(validator.field) = {msg_exists : true}]; } service Simple{ rpc Route (InnerMessage) returns (OuterMessage){}; }
代码import \"github.com/mwitkow/go-proto-validators/validator.proto\",文件validator.proto需要import \"google/protobuf/descriptor.proto\";包,不然会报错。
google/protobuf地址:
https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto
把src文件夹中的protobuf目录下载到GOPATH目录下。
2.编译simple.proto文件
go get github.com/mwitkow/go-proto-validators/protoc-gen-govalidators
指令编译:
protoc --govalidators_out=. --go_out=plugins=grpc:./ ./simple.proto
或者使用VSCode-proto3插件,第一篇有介绍。只需要添加\"--govalidators_out=.\"即可。
// vscode-proto3插件配置 \"protoc\": { // protoc.exe所在目录 \"path\": \"C:\\\\Go\\\\bin\\\\protoc.exe\", // 保存时自动编译 \"compile_on_save\": true, \"options\": [ // go编译输出指令 \"--go_out=plugins=grpc:.\", \"--govalidators_out=.\" ] },
编译完成后,自动生成simple.pb.go和simple.validator.pb.go文件,simple.pb.go文件不再介绍,我们看下simple.validator.pb.go文件。
// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: go-grpc-example/9-grpc_proto_validators/proto/simple.proto package proto import ( fmt \"fmt\" math \"math\" proto \"github.com/golang/protobuf/proto\" _ \"github.com/mwitkow/go-proto-validators\" regexp \"regexp\" github_com_mwitkow_go_proto_validators \"github.com/mwitkow/go-proto-validators\" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf func (this *InnerMessage) Validate() error { if !(this.SomeInteger > 0) { return github_com_mwitkow_go_proto_validators.FieldError(\"SomeInteger\", fmt.Errorf(`value \'%v\' must be greater than \'0\'`, this.SomeInteger)) } if !(this.SomeInteger < 100) { return github_com_mwitkow_go_proto_validators.FieldError(\"SomeInteger\", fmt.Errorf(`value \'%v\' must be less than \'100\'`, this.SomeInteger)) } if !(this.SomeFloat >= 0) { return github_com_mwitkow_go_proto_validators.FieldError(\"SomeFloat\", fmt.Errorf(`value \'%v\' must be greater than or equal to \'0\'`, this.SomeFloat)) } if !(this.SomeFloat <= 1) { return github_com_mwitkow_go_proto_validators.FieldError(\"SomeFloat\", fmt.Errorf(`value \'%v\' must be lower than or equal to \'1\'`, this.SomeFloat)) } return nil } var _regex_OuterMessage_ImportantString = regexp.MustCompile(`^[a-z]{2,5}$`) func (this *OuterMessage) Validate() error { if !_regex_OuterMessage_ImportantString.MatchString(this.ImportantString) { return github_com_mwitkow_go_proto_validators.FieldError(\"ImportantString\", fmt.Errorf(`value \'%v\' must be a string conforming to regex \"^[a-z]{2,5}$\"`, this.ImportantString)) } if nil == this.Inner { return github_com_mwitkow_go_proto_validators.FieldError(\"Inner\", fmt.Errorf(\"message must exist\")) } if this.Inner != nil { if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Inner); err != nil { return github_com_mwitkow_go_proto_validators.FieldError(\"Inner\", err) } } return nil }
里面自动生成了message中属性的验证规则。
grpcServer := grpc.NewServer(cred.TLSInterceptor(), grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( grpc_validator.StreamServerInterceptor(), grpc_auth.StreamServerInterceptor(auth.AuthInterceptor), grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()), grpc_recovery.StreamServerInterceptor(recovery.RecoveryInterceptor()), )), grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( grpc_validator.UnaryServerInterceptor(), grpc_auth.UnaryServerInterceptor(auth.AuthInterceptor), grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()), grpc_recovery.UnaryServerInterceptor(recovery.RecoveryInterceptor()), )), )
运行后,当输入数据验证失败后,会有以下错误返回
Call Route err: rpc error: code = InvalidArgument desc = invalid field SomeInteger: value \'101\' must be less than \'100\'
enum验证
syntax = \"proto3\"; package proto; import \"github.com/mwitkow/go-proto-validators/validator.proto\"; message SomeMsg { Action do = 1 [(validator.field) = {is_in_enum : true}]; } enum Action { ALLOW = 0; DENY = 1; CHILL = 2; }
UUID验证
syntax = \"proto3\"; package proto; import \"github.com/mwitkow/go-proto-validators/validator.proto\"; message UUIDMsg { // user_id must be a valid version 4 UUID. string user_id = 1 [(validator.field) = {uuid_ver: 4, string_not_empty: true}]; }
go-grpc-middleware中grpc_validator集成go-proto-validators,我们只需要在编写proto时设好验证规则,并把grpc_validator添加到gRPC服务端,就能完成gRPC的数据验证,很简单也很方便。
教程源码地址:https://github.com/Bingjian-Zhu/go-grpc-example
以上就是Go gRPC服务proto数据验证进阶教程的详细内容,更多关于Go gRPC服务proto数据验证的资料请关注脚本之家其它相关文章!