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/tree/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
Go gRPC进阶-proto数据验证(九)的更多相关文章
- Go gRPC进阶-gRPC转换HTTP(十)
前言 我们通常把RPC用作内部通信,而使用Restful Api进行外部通信.为了避免写两套应用,我们使用grpc-gateway把gRPC转成HTTP.服务接收到HTTP请求后,grpc-gatew ...
- Java实战之01Struts2-03属性封装、类型转换、数据验证
九.封装请求正文到对象中 1.静态参数封装 在struts.xml配置文件中,给动作类注入值.调用的是setter方法. 原因:是由一个staticParams的拦截器完成注入的. 2.动态参数封装: ...
- 【WPF】数据验证
原文:[WPF]数据验证 引言 数据验证在任何用户界面程序中都是不可缺少的一部分.在WPF中,数据验证更是和绑定紧紧联系在一起,下面简单介绍MVVM模式下常用的几种验证方式. 错误信息显示 ...
- 05:ModelForm 数据验证 & 生成html & 数据库操作
目录:Django其他篇 01:Django基础篇 02:Django进阶篇 03:Django数据库操作--->Model 04: Form 验证用户数据 & 生成html 05:Mo ...
- 我这么玩Web Api(二):数据验证,全局数据验证与单元测试
目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试 一.模型状态 - ModelState 我理解 ...
- MVC 数据验证
MVC 数据验证 前一篇说了MVC数据验证的例子,这次来详细说说各种各样的验证注解.System.ComponentModel.DataAnnotations 一.基础特性 一.Required 必填 ...
- kpvalidate开辟验证组件,通用Java Web请求服务器端数据验证组件
小菜利用工作之余编写了一款Java小插件,主要是用来验证Web请求的数据,是在服务器端进行验证,不是简单的浏览器端验证. 小菜编写的仅仅是一款非常初级的组件而已,但小菜为它写了详细的说明文档. 简单介 ...
- MVC3 数据验证用法之密码验证设计思路
描述:MVC数据验证使用小结 内容:display,Required,stringLength,Remote,compare,RegularExpression 本人最近在公司用mvc做了一个修改密码 ...
- jQuery MiniUI开发系列之:数据验证
在开发应用系统界面时,往往需要进行很多.复杂的数据验证,当填写的数据符合规定,才能提交保存. jQuery MiniUI提供了比较完美的表单数据验证和错误显示的方式. 常见的表单控件,都有一个验证事件 ...
随机推荐
- Django HttpResponse
HttpResponse 概述:给浏览器返回数据 HttpRequest对象是由django创建的,HttpResponse对象由程序员创建 用法 1:不调用模板,直接返回数据. 例: def get ...
- vue命令式组件和插件编写
一直在写各种业务,好多基本用法都忘记了,回顾一下: 一.vue各种UI库里的命令式组件比如element-ui里Notification组件,可以这样调用 this.$notify({ title: ...
- hive面试题
1. Hive数据倾斜原因: key分布不均匀 业务数据本身的特性 SQL语句造成数据倾斜解决方法hive设置hive.map.aggr=true和hive.groupby.skewindata=tr ...
- apache 自带的ab.exe 测试网站的并发量(网站压力测试)
AB(ApacheBench) 是 Apache 自带的超文本传输协议 (HTTP) 性能测试工具. 其设计意图是描绘当前所安装的 Apache 的执行性能, 主要是显示 Apache 每秒可以处理多 ...
- 图像配准:从SIFT到深度学习
图像配准(Image Registration)是计算机视觉中的基本步骤.在本文中,我们首先介绍基于OpenCV的方法,然后介绍深度学习的方法. 什么是图像配准 图像配准就是找到一幅图像像素到另一 ...
- WeChat-SmallProgram:组件 scroll-view 横向和纵向 案例
scroll-view为滚动视图,分为水平滚动和垂直滚动.注意滚动视图垂直滚动时一定要设置高度否则的话scroll-view不会生效. 滚动视图常用的地方一般都是Item项比较多的界面,比如我的模块 ...
- windows server 2016 远程桌面mstsc DPI(更改文本、应用和其他项目大小) 设置
windows server 2016 远程桌面mstsc DPI 设置 在高分辨率机器2K,4K,8K,登入使用window远程桌面mstsc时,登入后虽然分辨率变成了和cilent一样分辨率 但是 ...
- shell大全
1.shell判断文件是否存在 http://www.cnblogs.com/sunyubo/archive/2011/10/17/2282047.html
- cut-trailing-bytes:二进制尾部去0小工具
背景 之前的文章 二进制文件处理之尾部补0和尾部去0 中介绍了一种使用 sed 去除二进制文件尾部的 NULL(十六进制0x00)字节的方法. 最近发现这种方法有局限性,无法处理较大的文件.因为 se ...
- 使用golang理解mysql的两阶段提交
使用golang理解mysql的两阶段提交 文章源于一个问题:如果我们现在有两个mysql实例,在我们要尽量简单地完成分布式事务,怎么处理? 场景重现 比如我们现在有两个数据库,mysql3306和m ...