Skip to content
本页目录

gRPC ​

gRPC github 地址 https://github.com/grpc/grpc

metadata ​

go
package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata" 

	"rpc_demo/metadata/proto"
)

func main() {
	conn, _ := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
	defer conn.Close()
	client := hello.NewHelloServiceClient(conn)
	md := metadata.New(map[string]string{ 
		"name":     "shibin", 
		"password": "123456", 
	}) 
	ctx := metadata.NewOutgoingContext(context.Background(), md)                       
	r, _ := client.SayHello(ctx, &hello.HelloRequest{Name: "shibin"})                  
	r, _ := client.SayHello(context.Background(), &hello.HelloRequest{Name: "shibin"}) 
	fmt.Println(r.Status)
}

服务端获取 metadata

go
func (s *Server) SayHello(ctx context.Context, req *hello.HelloRequest) (*hello.HelloResponse, error) {
	md, ok := metadata.FromIncomingContext(ctx) 
	if ok { 
		for key, val := range md { 
			fmt.Println(key, val) 
		} 
	} 

	return &hello.HelloResponse{
		Status: 1,
	}, nil
}

拦截器 ​

服务端 ​

可以通过 grpc.NewServer 传递拦截器

go
func interceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { 
	md, ok := metadata.FromIncomingContext(ctx) 
	if !ok { 
		return resp, status.Error(codes.Unauthenticated, "无 token 认证信息") 
	} 
	var token string 
	if val, ok := md["token"]; ok { 
		token = val[0] 
	} 
	fmt.Println("token", token) 
	res, err := handler(ctx, req) 
	fmt.Println(time.Now()) 
	return res, err 
} 

func main() {
	s := grpc.NewServer(grpc.UnaryInterceptor(interceptor)) 
	s :=  grpc.NewServer() 
	hello.RegisterHelloServiceServer(s, &Server{})
	serve, _ := net.Listen("tcp", "0.0.0.0:8080")
	_ = s.Serve(serve)
}

客户端 ​

可以通过 grpc.Dial 的第三个参数来传递拦截器

go
...
func main() {
	interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { 
		fmt.Println("发送了请求") 
		err := invoker(ctx, method, req, reply, cc, opts...) 
		fmt.Println(time.Now()) 
		return err 
	} 

	conn, _ := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(interceptor)) 
	conn, _ := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials())) 
	defer conn.Close()
	client := hello.NewHelloServiceClient(conn)
	r, _ := client.SayHello(context.Background(), &hello.HelloRequest{Name: "shibin"})
	fmt.Println(r.Status)
}

也可以使用下面的方式

go
type customCredentinal struct { 
} 

func (c customCredentinal) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { 
	fmt.Println("发送了请求") 
	return map[string]string{ 
		"token": "xxxxxdfsdf", 
	}, nil 
} 
func (c customCredentinal) RequireTransportSecurity() bool { 
	return false 
} 

func main() {
	var opts []grpc.DialOption 
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))  
	opts = append(opts, grpc.WithPerRPCCredentials(customCredentinal{})) // grpc.Dial 的第三个参数 
	conn, _ := grpc.Dial("localhost:8080", opts...)
	defer conn.Close()
	client := hello.NewHelloServiceClient(conn)
	r, _ := client.SayHello(context.Background(), &hello.HelloRequest{Name: "shibin"}) 
	fmt.Println(r.Status)
}

验证器 ​

我们在 proto 文件中可以通过类型来限制传递数据的类型,但不能限制数据类型的长度、大小等。比如用户传递的用户名必须是 3-10 位等,这时我们就需要使用验证器

验证器可以使用 protoc-gen-validate

protoc-gen-validate 下载 ​

  • windows下载地址 ,打开后选择对应版本进行下载。下载后将 .exe 拷贝到 GOPATH 目录下的 bin 文件中,可以使用 go env 命令查看 GOPATH 目录
  • Mac 和 Linux 可以从 GitHub Releases 下载 ,也可以使用下面命令
bash
# fetches this repo into $GOPATH
go get -d github.com/envoyproxy/protoc-gen-validate
# installs PGV into $GOPATH/bin
make build

使用 ​

可以从 github 上 validate/validate.proto 将 proto 文件拷贝到项目中

也可以拷贝下面 proto 代码到项目文件中
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;
}

然后在项目中导入 validate.proto 文件

proto
syntax = "proto3";
import "validate.proto"; 
option go_package = "./;user";

message Person {
	// 邮箱校验
  string email = 2 [(validate.rules).string.email = true];
	// 名字 3-20 位
  string name = 3 [(validate.rules).string = {
    min_len: 3,
    max_len: 20
  }];
}

具体验证规则可以在 github 上查看

编译 proto 文件

bash
 protoc --go_out=. \
 --go-grpc_out=require_unimplemented_servers=false:. \
 --validate_out=lang=go:. user.proto

在服务端使用,可以在拦截器中使用 validate

go
package main

import (
	"fmt"
	"context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net"
	"rpc_demo/validate/protoc"
)

type Server struct {
}

func (s *Server) SayHello(context context.Context, req *user.Person) (*user.Person, error) {
	return req, nil
}

type Validator interface {
	Validate() error
}

func main() {
	interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		if r, ok := req.(Validator); ok {
			if err := r.Validate(); err != nil {
				return nil, status.Error(codes.InvalidArgument, err.Error())
			}
		}
		return handler(ctx, req)
	}
	g := grpc.NewServer(grpc.UnaryInterceptor(interceptor))
	user.RegisterUserServer(g, &Server{})
	lis, _ := net.Listen("tcp", "localhost:8080")
	g.Serve(lis)
}

状态码 ​

grpc 状态码说明 https://github.com/grpc/grpc/blob/master/doc/statuscodes.md

异常处理 ​

错误处理 ​

go
func main() {
	interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		if r, ok := req.(Validator); ok {
			if err := r.Validate(); err != nil {
				return nil, status.Error(codes.InvalidArgument, err.Error())
			}
		}
		return handler(ctx, req)
	}
	g := grpc.NewServer(grpc.UnaryInterceptor(interceptor))
	user.RegisterUserServer(g, &Server{})
	lis, _ := net.Listen("tcp", "localhost:8080")
	g.Serve(lis)
}

客户端获取错误信息

go
func main() {
	conn, _ := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))

	defer conn.Close()
	client := user.NewUserClient(conn)

	r, err := client.SayHello(context.Background(), &user.Person{
		Email: "aaa@qq.com",
		Name:  "a",
	})
	if err != nil {
		if st, ok := status.FromError(err); ok {
			fmt.Println(st.Message())
		}
	}
	fmt.Println(r)
}

超时机制 ​

go
 ...
 	ctx, _ := context.WithTimeout(context.Background(), time.Second * 3)
	r, err := client.SayHello(ctx, &user.Person{
		Email: "aaa@gmail.com",
		Name:  "shibin",
	})
...