Go gRPC进阶

前言

上篇介绍了go-grpc-middlewaregrpc_zapgrpc_authgrpc_recovery使用,本篇将介绍grpc_validator,它可以对gRPC数据的输入和输出进行验证。

创建proto文件,添加验证规则

这里使用第三方插件go-proto-validators自动生成验证规则。

go get github.com/mwitkow/go-proto-validators

1.新建simple.proto文件

1syntax = "proto3"; 2 3package proto; 4 5import "github.com/mwitkow/go-proto-validators/validator.proto"; 6 7message InnerMessage { 8 // some_integer can only be in range (1, 100). 9 int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}]; 10 // some_float can only be in range (0;1). 11 double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}]; 12} 13 14message OuterMessage { 15 // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). 16 string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; 17 // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage. 18 InnerMessage inner = 2 [(validator.field) = {msg_exists : true}]; 19} 20 21service Simple{ 22 rpc Route (InnerMessage) returns (OuterMessage){}; 23}

代码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=."即可。

1 // vscode-proto3插件配置 2 "protoc": { 3 // protoc.exe所在目录 4 "path": "C:\\Go\\bin\\protoc.exe", 5 // 保存时自动编译 6 "compile_on_save": true, 7 "options": [ 8 // go编译输出指令 9 "--go_out=plugins=grpc:.", 10 "--govalidators_out=." 11 ] 12 },

编译完成后,自动生成simple.pb.gosimple.validator.pb.go文件,simple.pb.go文件不再介绍,我们看下simple.validator.pb.go文件。

1// Code generated by protoc-gen-gogo. DO NOT EDIT. 2// source: go-grpc-example/9-grpc_proto_validators/proto/simple.proto 3 4package proto 5 6import ( 7 fmt "fmt" 8 math "math" 9 proto "github.com/golang/protobuf/proto" 10 _ "github.com/mwitkow/go-proto-validators" 11 regexp "regexp" 12 github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators" 13) 14 15// Reference imports to suppress errors if they are not otherwise used. 16var _ = proto.Marshal 17var _ = fmt.Errorf 18var _ = math.Inf 19 20func (this *InnerMessage) Validate() error { 21 if !(this.SomeInteger > 0) { 22 return github_com_mwitkow_go_proto_validators.FieldError("SomeInteger", fmt.Errorf(`value '%v' must be greater than '0'`, this.SomeInteger)) 23 } 24 if !(this.SomeInteger < 100) { 25 return github_com_mwitkow_go_proto_validators.FieldError("SomeInteger", fmt.Errorf(`value '%v' must be less than '100'`, this.SomeInteger)) 26 } 27 if !(this.SomeFloat >= 0) { 28 return github_com_mwitkow_go_proto_validators.FieldError("SomeFloat", fmt.Errorf(`value '%v' must be greater than or equal to '0'`, this.SomeFloat)) 29 } 30 if !(this.SomeFloat <= 1) { 31 return github_com_mwitkow_go_proto_validators.FieldError("SomeFloat", fmt.Errorf(`value '%v' must be lower than or equal to '1'`, this.SomeFloat)) 32 } 33 return nil 34} 35 36var _regex_OuterMessage_ImportantString = regexp.MustCompile(`^[a-z]{2,5}$`) 37 38func (this *OuterMessage) Validate() error { 39 if !_regex_OuterMessage_ImportantString.MatchString(this.ImportantString) { 40 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)) 41 } 42 if nil == this.Inner { 43 return github_com_mwitkow_go_proto_validators.FieldError("Inner", fmt.Errorf("message must exist")) 44 } 45 if this.Inner != nil { 46 if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(this.Inner); err != nil { 47 return github_com_mwitkow_go_proto_validators.FieldError("Inner", err) 48 } 49 } 50 return nil 51}

里面自动生成了message中属性的验证规则。

grpc_validator验证拦截器添加到服务端

1grpcServer := grpc.NewServer(cred.TLSInterceptor(), 2 grpc.StreamInterceptor(grpc_middleware.ChainStreamServer( 3 grpc_validator.StreamServerInterceptor(), 4 grpc_auth.StreamServerInterceptor(auth.AuthInterceptor), 5 grpc_zap.StreamServerInterceptor(zap.ZapInterceptor()), 6 grpc_recovery.StreamServerInterceptor(recovery.RecoveryInterceptor()), 7 )), 8 grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer( 9 grpc_validator.UnaryServerInterceptor(), 10 grpc_auth.UnaryServerInterceptor(auth.AuthInterceptor), 11 grpc_zap.UnaryServerInterceptor(zap.ZapInterceptor()), 12 grpc_recovery.UnaryServerInterceptor(recovery.RecoveryInterceptor()), 13 )), 14 )

运行后,当输入数据验证失败后,会有以下错误返回

Call Route err: rpc error: code = InvalidArgument desc = invalid field SomeInteger: value '101' must be less than '100'

其他类型验证规则设置

enum验证

1syntax = "proto3"; 2package proto; 3import "github.com/mwitkow/go-proto-validators/validator.proto"; 4 5message SomeMsg { 6 Action do = 1 [(validator.field) = {is_in_enum : true}]; 7} 8 9enum Action { 10 ALLOW = 0; 11 DENY = 1; 12 CHILL = 2; 13}

UUID验证

1syntax = "proto3"; 2package proto; 3import "github.com/mwitkow/go-proto-validators/validator.proto"; 4 5message UUIDMsg { 6 // user_id must be a valid version 4 UUID. 7 string user_id = 1 [(validator.field) = {uuid_ver: 4, string_not_empty: true}]; 8}

总结

go-grpc-middlewaregrpc_validator集成go-proto-validators,我们只需要在编写proto时设好验证规则,并把grpc_validator添加到gRPC服务端,就能完成gRPC的数据验证,很简单也很方便。

教程源码地址:https://github.com/Bingjian-Zhu/go-grpc-example

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

Go gRPC进阶 - HelloWorld