Go gRPC进阶-proto数据验证(九)
source link: https://studygolang.com/articles/28156
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
前言
上篇介绍了 go-grpc-middleware
的 grpc_zap
、 grpc_auth
和 grpc_recovery
使用,本篇将介绍 grpc_validator
,它可以对gRPC数据的输入和输出进行验证。
创建proto文件,添加验证规则
这里使用第三方插件 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/master/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
中属性的验证规则。
把 grpc_validator
验证拦截器添加到服务端
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
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK