Go gRPC服务proto数据验证进阶教程
前言
上篇介绍了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/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
中属性的验证规则。
把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
以上就是Go gRPC服务proto数据验证进阶教程的详细内容,更多关于Go gRPC服务proto数据验证的资料请关注猪先飞其它相关文章!
原文出处:https://www.cnblogs.com/FireworksEasyCool/p/12761033.html
相关文章
- 在程序员中,尤其是go新手,经常听到的一个讨论话题是:如何处理错误,这篇文章主要给大家介绍了关于Go应用中优雅处理Error的一些相关技巧,需要的朋友可以参考下...2021-09-08
Django def clean()函数对表单中的数据进行验证操作
这篇文章主要介绍了Django def clean()函数对表单中的数据进行验证操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-09- 这篇文章主要介绍了golang官方嵌入文件到可执行程序,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-20
- 这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-05-11
- 这篇文章主要介绍了Go语言使用读写OPC详解,图文讲解的很清晰,有感兴趣的同学可以学习下...2021-03-05
- 这篇文章主要介绍了golang在GRPC中设置client的超时时间,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-27
- string与[]byte经常需要互相转化,普通转化会发生底层数据的复制,下面这篇文章主要给大家介绍了关于Go中string与[]byte高效互转的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下...2021-09-20
- 这篇文章主要介绍了Go项目的目录结构,对基础目录做了讲解,对项目开发中的其它目录也一并做了介绍,需要的朋友可以参考下...2020-05-01
- Go 语言提供的基础容器,免不了要查询容器中的数据,那么是如何实现遍历的呢?本文将会介绍几种常用容易的遍历及其使用。感兴趣的可以了解一下...2021-06-13
- 这篇文章主要介绍了创建第一个Go语言程序Hello,Go!本文详细的给出项目创建、代码编写的过程,同时讲解了GOPATH、Go install等内容,需要的朋友可以参考下...2020-05-01
- 这篇文章主要介绍了在Django中使用MQTT的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-05-10
- 这篇文章主要介绍了go语言中的Carbon库时间处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-05
- 这篇文章主要介绍了go嵌套匿名结构体的初始化详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-16
解决导入django_filters不成功问题No module named 'django_filter'
这篇文章主要介绍了解决导入django_filters不成功问题No module named 'django_filter',具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-15详解如何使用Docker部署Django+MySQL8开发环境
这篇文章主要介绍了详解如何使用Docker部署Django+MySQL8开发环境,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-07-19- 这篇文章主要介绍了Go语言json编码驼峰转下划线、下划线转驼峰的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-09
- 这篇文章主要介绍了Django 解决由save方法引发的错误,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-21
- 这篇文章主要介绍了django前端页面下拉选择框默认值设置方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-10
- 这篇文章主要介绍了django数据模型中null和blank的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-03
- 这篇文章主要介绍了Go 自定义package包设置与导入操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06