【GO】六、protobuf 与 GRPC (一)
Protobuf
protobuf 有诸多数据类型,其中要注意的一个是:在对可能有负值参与的运算中,尽量不使用 int32 而是使用 sint64,它的效率要优于 int32
如何在一个 Protobuf 文件中 import 另一个 protobuf 文件
创建目录结构:
proto
helloworld.proto
base.proto
helloworld.proto:
syntax = "proto3";
option go_package = ".;proto-bak";
import "base.proto";
// 另外,有一些内置的包可以直接引入,例如 Empty 就有通用的包,不需要自己再去手动定义
import "google/protobuf/empty.proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
// 此处要注意的问题:必须设置传入的参数,但有时候我们不需要参数,这就需要我们自己定义一个空的内容
rpc Ping(Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
base.proto
syntax = "proto3";
option go_package = ".;proto-bak";
import "base.proto";
// 另外,有一些内置的包可以直接引入,例如 Empty 就有通用的包,不需要自己再去手动定义
import "google/protobuf/empty.proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
// 此处要注意的问题:必须设置传入的参数,但有时候我们不需要参数,这就需要我们自己定义一个空的内容
rpc Ping(google.protobuf.Empty) returns (Pong);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
内嵌的 嵌套 message
message HelloReply {
string message = 1;
message Result {
string name = 1;
string url = 2;
}
// 复习:repeated 代表定义的是一个数组
repeated Result data = 2;
}
上面是一个内嵌 message 的例子
另外,我们内嵌的 message 不会像其他语言一样不能在外部访问,而是会将其改名生成:
HelloReply_Result 会生成这样一个结构体,以下划线作为分隔
注意,我们如果涉及到 import 其他的包,我们必须把我们需要的所有 proto 文件全部生成源码,否则是很有可能出现找不到包的情况的
enum 类型
enum Gender {
MALE = 0;
FEMALE = 1;
}
message HelloRequest {
string name = 1;
Gender g = 2;
}
使用 ENUM 对固定变量进行定义
map 类型
message HelloRequest {
string name = 1;
Gender g = 2;
map<string, string> mp = 3;
}
时间戳类型(timestamp)
使用时间戳类型需要优先引入对应的包
import "google/protobuf/timestamp.proto";
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "Chen",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "GoLang",
"Character": "Fast",
},
AddTime: timestamppb.New(time.Now()),
})
GRPC
GRPC 中的 metadata
metadata 相当于 http 的 header,其以 key / value 的形式存储信息,key 是一个 string , value 是一个 []string (切片)
metadata 实际上其实是一个 map[string][]string
其使用方式如下,client.go,这里省略了 proto:
package main
import (
"FirstGo/goon/grpc_test/proto"
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main() {
// 尝试拨号
conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
// 创建客户端
c := proto.NewGreeterClient(conn)
// metadata 的两种构建方式
// 1. .Pair 方式
//md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
// 2. .New 方式
md := metadata.New(map[string]string{
"name": "Chen",
"password": "4321",
})
ctx := metadata.NewOutgoingContext(context.Background(), md)
// 调用对应的方法
r, err := c.SayHello(ctx, &proto.HelloRequest{
Name: "Chen",
})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
server.go:
package main
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"net"
"google.golang.org/grpc"
"FirstGo/goon/grpc_test/proto-bak"
)
type Server struct{}
// 业务逻辑
// 第一个参数必须是context,error必须加
func (s *Server) SayHello(ctx context.Context, request *proto_bak.HelloRequest) (*proto_bak.HelloReply, error) {
// grpc metadata 的写法
md, ok := metadata.FromIncomingContext(ctx)
if ok {
fmt.Println("get metadata error")
}
// 若要使用 md 中的内容:注意我们存储的是一个 slice
if nameSlice, ok := md["name"]; ok {
fmt.Println(nameSlice)
for i, e := range nameSlice {
fmt.Println(i, e)
}
}
for key, val := range md {
fmt.Println("md中内容的输出: ", key, val)
}
return &proto_bak.HelloReply{
Message: "hello " + request.Name,
}, nil
}
func main() {
g := grpc.NewServer()
proto_bak.RegisterGreeterServer(g, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen: " + err.Error())
}
err = g.Serve(lis)
if err != nil {
panic("failed to start grpc: " + err.Error())
}
}
GRPC拦截器 - go语言
实践:
grpc_interpretor
proto
helloworld.proto
…(proto的衍生文件)
拦截的简单流程:
// 创建拦截器的逻辑
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// 这里的逻辑会在真正的请求被实现之前执行,这就是拦截器
fmt.Println("这是拦截器,会在真正的逻辑被执行之前执行")
// 这句的意思是,执行之前的逻辑,不进行拦截的拒绝
return handler(ctx, req)
}
// 创建拦截器,需要传进来的是一个函数
opt := grpc.UnaryInterceptor(interceptor)
// 要配置拦截器,就要向 grpc.NewServer 中添加对应的ServerOption参数,这个参数需要提前准备好
g := grpc.NewServer(opt)
另外,如果我们需要拦截器,但又希望他能持续的运行,我们可以这样:
func main() {
// 创建拦截器的逻辑
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// 这里的逻辑会在真正的请求被实现之前执行,这就是拦截器
fmt.Println("这是拦截器,会在真正的逻辑被执行之前执行")
fmt.Println("请求开始执行")
timeBefore := time.Now()
// 这句的意思是,执行之前的逻辑,不进行拦截的拒绝
// 这里就放行了,但是拦截器还没有结束,拦截器被挂起了,先执行业务逻辑
resp, err = handler(ctx, req)
timeDone := time.Now()
// 业务逻辑执行完毕,拦截器继续执行
fmt.Printf("执行完成, 程序执行耗时:%d", timeDone.Second()-timeBefore.Second())
return resp, err
}
// 创建拦截器,需要传进来的是一个函数
opt := grpc.UnaryInterceptor(interceptor)
// 要配置拦截器,就要向 grpc.NewServer 中添加对应的ServerOption参数,这个参数需要提前准备好
g := grpc.NewServer(opt)
具体的业务代码:
server.go:
package main
import (
"context"
"fmt"
"net"
time "time"
"google.golang.org/grpc"
"FirstGo/goon/grpc_test/proto-bak"
)
type Server struct{}
// 业务逻辑
// 第一个参数必须是context,error必须加
func (s *Server) SayHello(ctx context.Context, request *proto_bak.HelloRequest) (*proto_bak.HelloReply, error) {
time.Sleep(time.Second * 2)
return &proto_bak.HelloReply{
Message: "hello " + request.Name,
}, nil
}
func main() {
// 创建拦截器的逻辑
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// 这里的逻辑会在真正的请求被实现之前执行,这就是拦截器
fmt.Println("这是拦截器,会在真正的逻辑被执行之前执行")
fmt.Println("请求开始执行")
timeBefore := time.Now()
// 这句的意思是,执行之前的逻辑,不进行拦截的拒绝
// 这里就放行了,但是拦截器还没有结束,拦截器被挂起了,先执行业务逻辑
resp, err = handler(ctx, req)
timeDone := time.Now()
// 业务逻辑执行完毕,拦截器继续执行
fmt.Printf("执行完成, 程序执行耗时:%d", timeDone.Second()-timeBefore.Second())
return resp, err
}
// 创建拦截器,需要传进来的是一个函数
opt := grpc.UnaryInterceptor(interceptor)
// 要配置拦截器,就要向 grpc.NewServer 中添加对应的ServerOption参数,这个参数需要提前准备好
g := grpc.NewServer(opt)
proto_bak.RegisterGreeterServer(g, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen: " + err.Error())
}
err = g.Serve(lis)
if err != nil {
panic("failed to start grpc: " + err.Error())
}
}
client.go(包括客户端拦截器):
package main
import (
"context"
"fmt"
"time"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/timestamppb"
"FirstGo/goon/grpc_test/proto"
)
func main() {
// 生成拦截器,固定写法
interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
start := time.Now()
// 执行逻辑
// 实参的传递中,后面加三个点的意思是,将slice切成一个个的元素进行传递
err := invoker(ctx, method, req, reply, cc, opts...)
fmt.Printf("耗时:%s", time.Since(start)) // time.Since(time)表示的是从传入的时间到现在的时间
return err
}
// 将拦截器配置进来
opt := grpc.WithUnaryInterceptor(interceptor)
// 尝试拨号,这里的拨号要传入拦截可以使用下面的方式:
// 将所有的拦截器都形成一个数组,一起传入,这样更清晰
var opts []grpc.DialOption
opts = append(opts, grpc.WithInsecure())
opts = append(opts, opt)
conn, err := grpc.Dial("127.0.0.1:8080", opts...) // 然后再将形成的 slice 以 ... 进行拆分传入
if err != nil {
panic(err)
}
defer conn.Close()
// 创建客户端
c := proto.NewGreeterClient(conn)
// 调用对应的方法
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "Chen",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "GoLang",
"Character": "Fast",
},
AddTime: timestamppb.New(time.Now()),
})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
helloworld.proto:
syntax = "proto3";
option go_package = ".;proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
使用metadata和拦截器进行登录信息验证的实例
使用 metadata 实现不改变 message 结构的需求
使用 拦截器 实现不改变业务代码逻辑的需求
进而实现在外层进行Auth验证,而无需每次都特意在message中携带登录信息或者修改业务代码的效果
对于错误信息的简单处理与放行机制:
md, ok := metadata.FromIncomingContext(ctx)
fmt.Println(md)
// ok 若为 true 则代表出现问题,需要进入错误处理机制
if !ok {
// 未取到信息
return resp, status.Error(codes.Unauthenticated, "无认证信息")
}
创建文件目录:
grpc_token_auth_test
proto
略
server
server.go
client
client.go
client.go(老)
老版本 客户端拦截器写法:
package main
import (
"context"
"fmt"
"google.golang.org/grpc/metadata"
"time"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/timestamppb"
"FirstGo/goon/grpc_test/proto"
)
func main() {
// 生成拦截器,固定写法
interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
start := time.Now()
md := metadata.New(map[string]string{
"appid": "101010111",
"appkey": "i am key",
})
// 将metadata 赋予进来
ctx = metadata.NewOutgoingContext(context.Background(), md)
// 执行逻辑
// 实参的传递中,后面加三个点的意思是,将slice切成一个个的元素进行传递
err := invoker(ctx, method, req, reply, cc, opts...)
fmt.Printf("耗时:%s", time.Since(start)) // time.Since(time)表示的是从传入的时间到现在的时间
return err
}
// 将拦截器配置进来
opt := grpc.WithUnaryInterceptor(interceptor)
// 尝试拨号,这里的拨号要传入拦截可以使用下面的方式:
// 将所有的拦截器都形成一个数组,一起传入,这样更清晰
var opts []grpc.DialOption
opts = append(opts, grpc.WithInsecure())
opts = append(opts, opt)
conn, err := grpc.Dial("127.0.0.1:8080", opts...) // 然后再将形成的 slice 以 ... 进行拆分传入
if err != nil {
panic(err)
}
defer conn.Close()
// 创建客户端
c := proto.NewGreeterClient(conn)
// 调用对应的方法
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "Chen",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "GoLang",
"Character": "Fast",
},
AddTime: timestamppb.New(time.Now()),
})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
使用 WithPerRPCCredentials 进行进一步简化:
client.go(新)
package main
import (
"context"
"fmt"
"time"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/timestamppb"
"FirstGo/goon/grpc_test/proto"
)
/*
使用 WithPerRPCCredentials 需要定义一个 类似于类一样的结构体,用于构建拦截器, 这里是 customCredential
令其实现两个对应的接口,这个接口可以在 WithPerRPCCredentials 的参数中找
*/
type customCredential struct{}
// 真正的拦截器逻辑
func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
// 这里 return 的就是发送的数据
return map[string]string{
"appid": "101010111",
"appkey": "i am key",
}, nil
}
// 这里是传输安全协定,这里先不考虑
func (c customCredential) RequireTransportSecurity() bool {
return false
}
func main() {
// 新版的拦截器写法,更简单的写法
opt := grpc.WithPerRPCCredentials(customCredential{})
// 尝试拨号,这里的拨号要传入拦截可以使用下面的方式:
// 将所有的拦截器都形成一个数组,一起传入,这样更清晰
var opts []grpc.DialOption
opts = append(opts, grpc.WithInsecure())
opts = append(opts, opt)
conn, err := grpc.Dial("127.0.0.1:8080", opts...) // 然后再将形成的 slice 以 ... 进行拆分传入
if err != nil {
panic(err)
}
defer conn.Close()
// 创建客户端
c := proto.NewGreeterClient(conn)
// 调用对应的方法
r, err := c.SayHello(context.Background(), &proto.HelloRequest{
Name: "Chen",
G: proto.Gender_FEMALE,
Mp: map[string]string{
"name": "GoLang",
"Character": "Fast",
},
AddTime: timestamppb.New(time.Now()),
})
if err != nil {
panic(err)
}
fmt.Println(r.Message)
}
server.go
package main
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"net"
time "time"
"google.golang.org/grpc"
"FirstGo/goon/grpc_test/proto-bak"
)
type Server struct{}
// 业务逻辑
// 第一个参数必须是context,error必须加
func (s *Server) SayHello(ctx context.Context, request *proto_bak.HelloRequest) (*proto_bak.HelloReply, error) {
time.Sleep(time.Second * 2)
return &proto_bak.HelloReply{
Message: "hello " + request.Name,
}, nil
}
func main() {
// 创建拦截器的逻辑
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
// 这里的逻辑会在真正的请求被实现之前执行,这就是拦截器
fmt.Println("这是拦截器,会在真正的逻辑被执行之前执行")
md, ok := metadata.FromIncomingContext(ctx)
fmt.Println(md)
// ok 若为 true 则代表出现问题,需要进入错误处理机制
if !ok {
// 未取到信息
return resp, status.Error(codes.Unauthenticated, "无认证信息")
}
// 从 metadata 中取值
var (
appid string
appkey string
)
if va1, ok := md["appid"]; ok {
appid = va1[0]
}
if va1, ok := md["appkey"]; ok {
appkey = va1[0]
}
fmt.Println(appid, appkey)
// 这里不匹配就会被拦截
if appid != "101010111" || appkey != "i am key" {
// 在这里返回了,就不会再执行后面的真正的逻辑了,通过这种形式打成了拦截的效果
return resp, status.Error(codes.Unauthenticated, "认证信息有误")
}
fmt.Println("请求开始执行")
timeBefore := time.Now()
// 这句的意思是,执行之前的逻辑,不进行拦截的拒绝
// 这里就放行了,但是拦截器还没有结束,拦截器被挂起了,先执行业务逻辑
resp, err = handler(ctx, req)
timeDone := time.Now()
// 业务逻辑执行完毕,拦截器继续执行
fmt.Printf("执行完成, 程序执行耗时:%d", timeDone.Second()-timeBefore.Second())
return resp, err
}
// 创建拦截器,需要传进来的是一个函数
opt := grpc.UnaryInterceptor(interceptor)
// 要配置拦截器,就要向 grpc.NewServer 中添加对应的ServerOption参数,这个参数需要提前准备好
g := grpc.NewServer(opt)
proto_bak.RegisterGreeterServer(g, &Server{})
lis, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic("failed to listen: " + err.Error())
}
err = g.Serve(lis)
if err != nil {
panic("failed to start grpc: " + err.Error())
}
}
GRPC 的验证器(实现表单验证功能)
使用 protoc-gen-validate 第三方库实现
我们在对应的网站下载 .exe 文件并将其放置在 go 环境目录的 bin 文件夹下:注意删除版本号
对于 验证器功能,针对于第三方库进行具体实现,不在这里做过多的介绍,在后面的项目中进行实际使用
复制下面的 validate.proto,每次都一样的文件:
syntax = "proto2";
package validate;
option go_package = "github.com/envoyproxy/protoc-gen-validate/validate";
option java_package = "io.envoyproxy.pgv.validate";
import "google/protobuf/descriptor.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
// Validation rules applied at the message level
extend google.protobuf.MessageOptions {
// Disabled nullifies any validation rules for this message, including any
// message fields associated with it that do support validation.
optional bool disabled = 1071;
// Ignore skips generation of validation methods for this message.
optional bool ignored = 1072;
}
// Validation rules applied at the oneof level
extend google.protobuf.OneofOptions {
// Required ensures that exactly one the field options in a oneof is set;
// validation fails if no fields in the oneof are set.
optional bool required = 1071;
}
// Validation rules applied at the field level
extend google.protobuf.FieldOptions {
// Rules specify the validations to be performed on this field. By default,
// no validation is performed against a field.
optional FieldRules rules = 1071;
}
// FieldRules encapsulates the rules for each type of field. Depending on the
// field, the correct set should be used to ensure proper validations.
message FieldRules {
optional MessageRules message = 17;
oneof type {
// Scalar Field Types
FloatRules float = 1;
DoubleRules double = 2;
Int32Rules int32 = 3;
Int64Rules int64 = 4;
UInt32Rules uint32 = 5;
UInt64Rules uint64 = 6;
SInt32Rules sint32 = 7;
SInt64Rules sint64 = 8;
Fixed32Rules fixed32 = 9;
Fixed64Rules fixed64 = 10;
SFixed32Rules sfixed32 = 11;
SFixed64Rules sfixed64 = 12;
BoolRules bool = 13;
StringRules string = 14;
BytesRules bytes = 15;
// Complex Field Types
EnumRules enum = 16;
RepeatedRules repeated = 18;
MapRules map = 19;
// Well-Known Field Types
AnyRules any = 20;
DurationRules duration = 21;
TimestampRules timestamp = 22;
}
}
// FloatRules describes the constraints applied to `float` values
message FloatRules {
// Const specifies that this field must be exactly the specified value
optional float const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional float lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional float lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional float gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional float gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated float in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated float not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// DoubleRules describes the constraints applied to `double` values
message DoubleRules {
// Const specifies that this field must be exactly the specified value
optional double const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional double lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional double lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional double gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional double gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated double in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated double not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// Int32Rules describes the constraints applied to `int32` values
message Int32Rules {
// Const specifies that this field must be exactly the specified value
optional int32 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional int32 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional int32 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional int32 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional int32 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated int32 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated int32 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// Int64Rules describes the constraints applied to `int64` values
message Int64Rules {
// Const specifies that this field must be exactly the specified value
optional int64 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional int64 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional int64 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional int64 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional int64 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated int64 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated int64 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// UInt32Rules describes the constraints applied to `uint32` values
message UInt32Rules {
// Const specifies that this field must be exactly the specified value
optional uint32 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional uint32 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional uint32 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional uint32 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional uint32 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated uint32 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated uint32 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// UInt64Rules describes the constraints applied to `uint64` values
message UInt64Rules {
// Const specifies that this field must be exactly the specified value
optional uint64 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional uint64 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional uint64 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional uint64 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional uint64 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated uint64 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated uint64 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// SInt32Rules describes the constraints applied to `sint32` values
message SInt32Rules {
// Const specifies that this field must be exactly the specified value
optional sint32 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional sint32 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional sint32 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional sint32 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional sint32 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated sint32 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated sint32 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// SInt64Rules describes the constraints applied to `sint64` values
message SInt64Rules {
// Const specifies that this field must be exactly the specified value
optional sint64 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional sint64 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional sint64 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional sint64 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional sint64 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated sint64 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated sint64 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// Fixed32Rules describes the constraints applied to `fixed32` values
message Fixed32Rules {
// Const specifies that this field must be exactly the specified value
optional fixed32 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional fixed32 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional fixed32 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional fixed32 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional fixed32 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated fixed32 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated fixed32 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// Fixed64Rules describes the constraints applied to `fixed64` values
message Fixed64Rules {
// Const specifies that this field must be exactly the specified value
optional fixed64 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional fixed64 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional fixed64 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional fixed64 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional fixed64 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated fixed64 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated fixed64 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// SFixed32Rules describes the constraints applied to `sfixed32` values
message SFixed32Rules {
// Const specifies that this field must be exactly the specified value
optional sfixed32 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional sfixed32 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional sfixed32 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional sfixed32 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional sfixed32 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated sfixed32 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated sfixed32 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// SFixed64Rules describes the constraints applied to `sfixed64` values
message SFixed64Rules {
// Const specifies that this field must be exactly the specified value
optional sfixed64 const = 1;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional sfixed64 lt = 2;
// Lte specifies that this field must be less than or equal to the
// specified value, inclusive
optional sfixed64 lte = 3;
// Gt specifies that this field must be greater than the specified value,
// exclusive. If the value of Gt is larger than a specified Lt or Lte, the
// range is reversed.
optional sfixed64 gt = 4;
// Gte specifies that this field must be greater than or equal to the
// specified value, inclusive. If the value of Gte is larger than a
// specified Lt or Lte, the range is reversed.
optional sfixed64 gte = 5;
// In specifies that this field must be equal to one of the specified
// values
repeated sfixed64 in = 6;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated sfixed64 not_in = 7;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 8;
}
// BoolRules describes the constraints applied to `bool` values
message BoolRules {
// Const specifies that this field must be exactly the specified value
optional bool const = 1;
}
// StringRules describe the constraints applied to `string` values
message StringRules {
// Const specifies that this field must be exactly the specified value
optional string const = 1;
// Len specifies that this field must be the specified number of
// characters (Unicode code points). Note that the number of
// characters may differ from the number of bytes in the string.
optional uint64 len = 19;
// MinLen specifies that this field must be the specified number of
// characters (Unicode code points) at a minimum. Note that the number of
// characters may differ from the number of bytes in the string.
optional uint64 min_len = 2;
// MaxLen specifies that this field must be the specified number of
// characters (Unicode code points) at a maximum. Note that the number of
// characters may differ from the number of bytes in the string.
optional uint64 max_len = 3;
// LenBytes specifies that this field must be the specified number of bytes
optional uint64 len_bytes = 20;
// MinBytes specifies that this field must be the specified number of bytes
// at a minimum
optional uint64 min_bytes = 4;
// MaxBytes specifies that this field must be the specified number of bytes
// at a maximum
optional uint64 max_bytes = 5;
// Pattern specifes that this field must match against the specified
// regular expression (RE2 syntax). The included expression should elide
// any delimiters.
optional string pattern = 6;
// Prefix specifies that this field must have the specified substring at
// the beginning of the string.
optional string prefix = 7;
// Suffix specifies that this field must have the specified substring at
// the end of the string.
optional string suffix = 8;
// Contains specifies that this field must have the specified substring
// anywhere in the string.
optional string contains = 9;
// NotContains specifies that this field cannot have the specified substring
// anywhere in the string.
optional string not_contains = 23;
// In specifies that this field must be equal to one of the specified
// values
repeated string in = 10;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated string not_in = 11;
// WellKnown rules provide advanced constraints against common string
// patterns
oneof well_known {
// Email specifies that the field must be a valid email address as
// defined by RFC 5322
bool email = 12;
// Hostname specifies that the field must be a valid hostname as
// defined by RFC 1034. This constraint does not support
// internationalized domain names (IDNs).
bool hostname = 13;
// Ip specifies that the field must be a valid IP (v4 or v6) address.
// Valid IPv6 addresses should not include surrounding square brackets.
bool ip = 14;
// Ipv4 specifies that the field must be a valid IPv4 address.
bool ipv4 = 15;
// Ipv6 specifies that the field must be a valid IPv6 address. Valid
// IPv6 addresses should not include surrounding square brackets.
bool ipv6 = 16;
// Uri specifies that the field must be a valid, absolute URI as defined
// by RFC 3986
bool uri = 17;
// UriRef specifies that the field must be a valid URI as defined by RFC
// 3986 and may be relative or absolute.
bool uri_ref = 18;
// Address specifies that the field must be either a valid hostname as
// defined by RFC 1034 (which does not support internationalized domain
// names or IDNs), or it can be a valid IP (v4 or v6).
bool address = 21;
// Uuid specifies that the field must be a valid UUID as defined by
// RFC 4122
bool uuid = 22;
// WellKnownRegex specifies a common well known pattern defined as a regex.
KnownRegex well_known_regex = 24;
}
// This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable
// strict header validation.
// By default, this is true, and HTTP header validations are RFC-compliant.
// Setting to false will enable a looser validations that only disallows
// \r\n\0 characters, which can be used to bypass header matching rules.
optional bool strict = 25 [default = true];
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 26;
}
// WellKnownRegex contain some well-known patterns.
enum KnownRegex {
UNKNOWN = 0;
// HTTP header name as defined by RFC 7230.
HTTP_HEADER_NAME = 1;
// HTTP header value as defined by RFC 7230.
HTTP_HEADER_VALUE = 2;
}
// BytesRules describe the constraints applied to `bytes` values
message BytesRules {
// Const specifies that this field must be exactly the specified value
optional bytes const = 1;
// Len specifies that this field must be the specified number of bytes
optional uint64 len = 13;
// MinLen specifies that this field must be the specified number of bytes
// at a minimum
optional uint64 min_len = 2;
// MaxLen specifies that this field must be the specified number of bytes
// at a maximum
optional uint64 max_len = 3;
// Pattern specifes that this field must match against the specified
// regular expression (RE2 syntax). The included expression should elide
// any delimiters.
optional string pattern = 4;
// Prefix specifies that this field must have the specified bytes at the
// beginning of the string.
optional bytes prefix = 5;
// Suffix specifies that this field must have the specified bytes at the
// end of the string.
optional bytes suffix = 6;
// Contains specifies that this field must have the specified bytes
// anywhere in the string.
optional bytes contains = 7;
// In specifies that this field must be equal to one of the specified
// values
repeated bytes in = 8;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated bytes not_in = 9;
// WellKnown rules provide advanced constraints against common byte
// patterns
oneof well_known {
// Ip specifies that the field must be a valid IP (v4 or v6) address in
// byte format
bool ip = 10;
// Ipv4 specifies that the field must be a valid IPv4 address in byte
// format
bool ipv4 = 11;
// Ipv6 specifies that the field must be a valid IPv6 address in byte
// format
bool ipv6 = 12;
}
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 14;
}
// EnumRules describe the constraints applied to enum values
message EnumRules {
// Const specifies that this field must be exactly the specified value
optional int32 const = 1;
// DefinedOnly specifies that this field must be only one of the defined
// values for this enum, failing on any undefined value.
optional bool defined_only = 2;
// In specifies that this field must be equal to one of the specified
// values
repeated int32 in = 3;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated int32 not_in = 4;
}
// MessageRules describe the constraints applied to embedded message values.
// For message-type fields, validation is performed recursively.
message MessageRules {
// Skip specifies that the validation rules of this field should not be
// evaluated
optional bool skip = 1;
// Required specifies that this field must be set
optional bool required = 2;
}
// RepeatedRules describe the constraints applied to `repeated` values
message RepeatedRules {
// MinItems specifies that this field must have the specified number of
// items at a minimum
optional uint64 min_items = 1;
// MaxItems specifies that this field must have the specified number of
// items at a maximum
optional uint64 max_items = 2;
// Unique specifies that all elements in this field must be unique. This
// contraint is only applicable to scalar and enum types (messages are not
// supported).
optional bool unique = 3;
// Items specifies the contraints to be applied to each item in the field.
// Repeated message fields will still execute validation against each item
// unless skip is specified here.
optional FieldRules items = 4;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 5;
}
// MapRules describe the constraints applied to `map` values
message MapRules {
// MinPairs specifies that this field must have the specified number of
// KVs at a minimum
optional uint64 min_pairs = 1;
// MaxPairs specifies that this field must have the specified number of
// KVs at a maximum
optional uint64 max_pairs = 2;
// NoSparse specifies values in this field cannot be unset. This only
// applies to map's with message value types.
optional bool no_sparse = 3;
// Keys specifies the constraints to be applied to each key in the field.
optional FieldRules keys = 4;
// Values specifies the constraints to be applied to the value of each key
// in the field. Message values will still have their validations evaluated
// unless skip is specified here.
optional FieldRules values = 5;
// IgnoreEmpty specifies that the validation rules of this field should be
// evaluated only if the field is not empty
optional bool ignore_empty = 6;
}
// AnyRules describe constraints applied exclusively to the
// `google.protobuf.Any` well-known type
message AnyRules {
// Required specifies that this field must be set
optional bool required = 1;
// In specifies that this field's `type_url` must be equal to one of the
// specified values.
repeated string in = 2;
// NotIn specifies that this field's `type_url` must not be equal to any of
// the specified values.
repeated string not_in = 3;
}
// DurationRules describe the constraints applied exclusively to the
// `google.protobuf.Duration` well-known type
message DurationRules {
// Required specifies that this field must be set
optional bool required = 1;
// Const specifies that this field must be exactly the specified value
optional google.protobuf.Duration const = 2;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional google.protobuf.Duration lt = 3;
// Lt specifies that this field must be less than the specified value,
// inclusive
optional google.protobuf.Duration lte = 4;
// Gt specifies that this field must be greater than the specified value,
// exclusive
optional google.protobuf.Duration gt = 5;
// Gte specifies that this field must be greater than the specified value,
// inclusive
optional google.protobuf.Duration gte = 6;
// In specifies that this field must be equal to one of the specified
// values
repeated google.protobuf.Duration in = 7;
// NotIn specifies that this field cannot be equal to one of the specified
// values
repeated google.protobuf.Duration not_in = 8;
}
// TimestampRules describe the constraints applied exclusively to the
// `google.protobuf.Timestamp` well-known type
message TimestampRules {
// Required specifies that this field must be set
optional bool required = 1;
// Const specifies that this field must be exactly the specified value
optional google.protobuf.Timestamp const = 2;
// Lt specifies that this field must be less than the specified value,
// exclusive
optional google.protobuf.Timestamp lt = 3;
// Lte specifies that this field must be less than the specified value,
// inclusive
optional google.protobuf.Timestamp lte = 4;
// Gt specifies that this field must be greater than the specified value,
// exclusive
optional google.protobuf.Timestamp gt = 5;
// Gte specifies that this field must be greater than the specified value,
// inclusive
optional google.protobuf.Timestamp gte = 6;
// LtNow specifies that this must be less than the current time. LtNow
// can only be used with the Within rule.
optional bool lt_now = 7;
// GtNow specifies that this must be greater than the current time. GtNow
// can only be used with the Within rule.
optional bool gt_now = 8;
// Within specifies that this field must be within this duration of the
// current time. This constraint can be used alone or with the LtNow and
// GtNow rules.
optional google.protobuf.Duration within = 9;
}
下面是一个实例 helloworld.proto:
syntax = "proto3";
option go_package = ".;proto";
import "validate.proto";
service Greeter{
rpc SayHello(Person) returns (Person);
}
message Person {
// 大于999
uint64 id = 1 [(validate.rules).uint64.gt = 999];
string email = 2 [(validate.rules).string.email = true];
string name = 3 [(validate.rules).string = {
pattern: "[\u4e00-\u9fa5]",
max_bytes: 30,
}];
Location home = 4 [(validate.rules).message.required = true];
message Location {
double lat = 1 [(validate.rules).double = {gte: -90, lte: 90}];
double lng = 2 [(validate.rules).double = {gte: -180, lte: 180}];
}
}
Validate的生成:
protoc -I . --go_out=. --go-grpc_out=require_unimplemented_servers=false:. --validate_out="lang=go:." ./helloworld.proto
p := New(proto.Person)
err := p.Validate()// 这个Validate方法就是被生成的,若验证成功,则 err 为 nil
原文地址:https://blog.csdn.net/weixin_41365204/article/details/136443643
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!