grpc的metadata---拦截器--验证器--状态码-yapi安装

转载来源:grpc的metadata---拦截器--验证器--状态码-yapi安装-CSDN博客

gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些在header中传递的数据,而这些数据就可以通过metadata来传递。
metadata是以key-value的形式存储数据的,其中key是string类型,value是[]string类型,即一个字符串切片类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周期是一次http请求,那么metadata的生命周期就是一次RPC调用。
metadata机制:源数据可以做权限验证

1. go中使用metadata

项目源代码路径:https://github.com/grpc/grpc-go/tree/master/metadata

项目文档:https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md

使用的go包:“google.golang.org/grpc/metadata”

新建methdata

MD 类型实际上是map,key是string,value是string类型的slice。

type MD map[string][]string

创建的时候可以像创建普通的map类型一样使用new关键字进行创建:

//第一种方式
md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
 
//第二种方式 key不区分大小写,会被统一转成小写
md := metadata.Pairs(
    "key1", "val1",
    "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
    "key2", "val2",
)

2)发送metadata

md := metadata.Pairs("key", "val")
 
// 新建一个有 metadata 的 context
ctx := metadata.NewOutgoingContext(context.Background(), md)
 
// 单向 RPC
response, err := client.SomeRPC(ctx, someRequest)

3)接收metadata

func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
    md, ok := metadata.FromIncomingContext(ctx)
    // do something with metadata
    }

client.go

package main

import (
	"awesomeProject123/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()

	//调用protobuf的函数客户端
	client := proto.NewGreeterClient(conn)

	//md := metadata.Pairs("timestamp", time.Now().Format())
	md := metadata.New(map[string]string{
		"name":     "aaads",
		"password": "asdasd",
		//"name":     "好好学习",
		//"password": "天天向上", 中文无法传过去
	})

	//新建一个有 metadata 的 context
	ctx := metadata.NewOutgoingContext(context.Background(), md)

	//调用sayHello
	sayHello, err := client.SayHello(ctx, &proto.HelloRequest{
		Name: "bobby",
	})
	if err != nil {
		return
	}

	fmt.Println(sayHello.Message)
}

server.go

package main

import (
	"awesomeProject123/grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"net"
)

type Server struct {
	*proto.UnimplementedGreeterServer
}

func (s *Server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

// SayHello ctx context.Context协程
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {

	md, ok := metadata.FromIncomingContext(ctx)

	if ok !=true{
		fmt.Println("get metadata error")
	}

	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(key, val)
	}

	return &proto.HelloReply{
		Message: "hello" + request.Name,
	}, nil
}

func main() {
	//new服务
	grpc1 := grpc.NewServer()

	//注册
	proto.RegisterGreeterServer(grpc1, &Server{})
	//监听
	listen, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		panic("failed  to listen:" + err.Error())
	}

	//启动 不会关闭
	err = grpc1.Serve(listen)
	if err != nil {
		panic("failed  to start:" + err.Error())
	}
}

proto

syntax = "proto3";
option go_package = ".;proto";
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}
//将 sessionid放入 放入cookie中 http协议
message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

//go语言中是生成一个文件, 也就只有python会生成两个文件

grpc拦截器-go语言–简单使用–一元拦截器

拦截器功能:所有接口都具有的功能==>1 访问时长,用户登录情况,反扒策略,作为预处理
拦截器应用场景

https://github.com/grpc-ecosystem/go-grpc-middleware

server.go

package main

import (
	"awesomeProject123/grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"net"
)

type Server struct {
	*proto.UnimplementedGreeterServer
}

func (s *Server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

// SayHello ctx context.Context协程
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	return &proto.HelloReply{
		Message: "hello" + request.Name,
	}, nil
}

func main() {
//拦截器
	interceptor := func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
		fmt.Println("接收到了一个新的请求")
		return handler(ctx, req)
	}
	//主要对于一元方法的拦截器
	option := grpc.UnaryInterceptor(interceptor)
	//new服务
	grpc1 := grpc.NewServer(option)

	//注册
	proto.RegisterGreeterServer(grpc1, &Server{})
	//监听
	listen, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		panic("failed  to listen:" + err.Error())
	}

	//启动 不会关闭
	err = grpc1.Serve(listen)
	if err != nil {
		panic("failed  to start:" + err.Error())
	}
}

client.go

package main

import (
	"awesomeProject123/grpc_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"time"
)

func main() {
//拦截器
	interceptor := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		start := time.Now()
		err := invoker(ctx, method, req, reply, cc, opts...)
		fmt.Printf("耗时:%s\n", time.Since(start))
		return err
	}

	var opts []grpc.DialOption
	opts = append(opts, grpc.WithInsecure())
	opts = append(opts, grpc.WithUnaryInterceptor(interceptor))

	//option := grpc.WithUnaryInterceptor(interceptor)

	//建立服务器连接
	//conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	conn, err := grpc.Dial("127.0.0.1:8080", opts...)
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	//调用protobuf的函数传进客户端
	client := proto.NewGreeterClient(conn)

	//调用sayHello
	sayHello, err := client.SayHello(context.Background(), &proto.HelloRequest{
		Name: "bobby",
	})
	if err != nil {
		return
	}

	fmt.Println(sayHello.Message)
}

通过拦截器和metadata实现grpc的auth认证(用户登录)–token认证

1:数据是否适合携带到message中?
2:你在携带的时候,每次调用都携带这两个信息吗?
不侵入之前的业务逻辑,可以同时使用拦截器和grpc功能

client.go–简单的使用

package main

import (
	"awesomeProject123/grpc+token_auth_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"time"
)

func main() {

	interceptor := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		start := time.Now()

		md := metadata.New(map[string]string{
			"appid":  "101010",
			"appkey": "I am key",
		})
		ctx = metadata.NewOutgoingContext(context.Background(), md)
		//fmt.Println(opts)
		err := invoker(ctx, method, req, reply, cc, opts...)
		fmt.Printf("耗时:%s\n", time.Since(start))
		return err
	}

	var opts []grpc.DialOption
	opts = append(opts, grpc.WithInsecure())
	opts = append(opts, grpc.WithUnaryInterceptor(interceptor))

	//option := grpc.WithUnaryInterceptor(interceptor)

	//建立服务器连接
	//conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	conn, err := grpc.Dial("127.0.0.1:8080", opts...)
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	//调用protobuf的函数传进客户端
	client := proto.NewGreeterClient(conn)

	//调用sayHello
	sayHello, err := client.SayHello(context.Background(), &proto.HelloRequest{
		Name: "bobby",
	})
	if err != nil {
		return
	}

	fmt.Println(sayHello.Message)
}

server.go–简单的使用

package main

import (
	"awesomeProject123/grpc+token_auth_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
	"net"
)

type Server struct {
	*proto.UnimplementedGreeterServer
}

func (s *Server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

// SayHello ctx context.Context协程
func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	return &proto.HelloReply{
		Message: "hello" + request.Name,
	}, nil
}

func main() {
	interceptor := func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
		fmt.Println("接收到了一个新的请求")
		md, ok := metadata.FromIncomingContext(ctx)

		fmt.Println("aa", ok)
		fmt.Println(md)
		if ok != true {
			//已经开始接触到grpc的错误的处理
			fmt.Println("get metadata error")
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}

		var (
			appid  string
			appkey string
		)

		if va1, ok := md["appid"]; ok {
			fmt.Println(va1)
			appid = va1[0]
		}

		if va1, ok := md["appkey"]; ok {
			fmt.Println(va1)
			appkey = va1[0]
		}

		if appid != "101010" || appkey != "I am key" {
			return resp, status.Error(codes.Unauthenticated, "无token认证信息")
		}

		return handler(ctx, req)
	}
	//主要对于一元方法的拦截器
	option := grpc.UnaryInterceptor(interceptor)
	//new服务
	grpc1 := grpc.NewServer(option)

	//注册
	proto.RegisterGreeterServer(grpc1, &Server{})
	//监听
	listen, err := net.Listen("tcp", "0.0.0.0:8080")
	if err != nil {
		panic("failed  to listen:" + err.Error())
	}

	//启动 不会关闭
	err = grpc1.Serve(listen)
	if err != nil {
		panic("failed  to start:" + err.Error())
	}
}

更简单的方法client.go

package main

import (
	"awesomeProject123/grpc+token_auth_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
)

type customCredential struct {
}

func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {

	return map[string]string{
		"appid":  "101010",
		"appkey": "I am key",
	}, nil
}

func (c customCredential) RequireTransportSecurity() bool {
	return false
}
func main() {
	var opts []grpc.DialOption
	opts = append(opts, grpc.WithInsecure())
	opts = append(opts, grpc.WithPerRPCCredentials(customCredential{}))

	//option := grpc.WithUnaryInterceptor(interceptor)

	//建立服务器连接
	//conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	conn, err := grpc.Dial("127.0.0.1:8080", opts...)
	if err != nil {
		panic(err)
	}

	defer conn.Close()

	//调用protobuf的函数传进客户端
	client := proto.NewGreeterClient(conn)

	//调用sayHello
	sayHello, err := client.SayHello(context.Background(), &proto.HelloRequest{
		Name: "bobby",
	})
	if err != nil {
		return
	}

	fmt.Println(sayHello.Message)
}

grpc的验证器

https://github.com/bufbuild/protoc-gen-validate

windows安装

https://oss.sonatype.org/content/repositories/snapshots/io/envoyproxy/protoc-gen-validate/protoc-gen-validate/0.4.2-SNAPSHOT/

需要新建validata.proto文件

https://github.com/envoyproxy/protoc-gen-validate/blob/master/validate/validate.proto

使用命令

 protoc --go_out=. --go-grpc_out=. --validate_out="lang=go:." .\helloworld.proto 

validata.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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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;
}

// 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
  // at a minimum
  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];
}

// 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;
  }
}

// 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;
}

// 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;
}

// 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";

import "validate.proto";
option go_package=".;proto";

service Greeter {
  rpc SayHello (Person) returns (Person);
}

message Person {
  uint64 id    = 1 [(validate.rules).uint64.gt    = 999];
  string email = 2 [(validate.rules).string.email = true];
  string mobile = 3 [(validate.rules).string = {
//    pattern:   "^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$",
//    max_bytes: 256,
    pattern:   "^1[3456789]\\d{9}$"
  }];
}

sever.go

package main

import (
	"context"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"net"

	"google.golang.org/grpc"

	"awesomeProject123/grpc_validate_test/proto"
)

type Server struct {
	*proto.UnimplementedGreeterServer
}

func (s *Server) mustEmbedUnimplementedGreeterServer() {
	//TODO implement me
	panic("implement me")
}

func (s *Server) SayHello(ctx context.Context, request *proto.Person) (*proto.Person,
	error) {
	return &proto.Person{
		Id: 32,
	}, nil
}

type Validator interface {
	Validate() error
}

func main() {

	var interceptor grpc.UnaryServerInterceptor
	interceptor = func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		// 继续处理请求
		//(proto.Person) 可以满足person的验证, 所有的接口 还有其他的接口那怎么办==>Validator转换为接口
		if r, ok := req.(Validator); ok {
			if err := r.Validate(); err != nil {
				return nil, status.Error(codes.InvalidArgument, err.Error())
			}
		}

		return handler(ctx, req)
	}
	var opts []grpc.ServerOption
	opts = append(opts, grpc.UnaryInterceptor(interceptor))

	g := grpc.NewServer(opts...)
	proto.RegisterGreeterServer(g, &Server{})
	lis, err := net.Listen("tcp", "0.0.0.0:50051")
	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 (
	"awesomeProject123/grpc_validate_test/proto"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

func main() {
	//stream
	conn, err := grpc.Dial("127.0.0.1:50051", grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c := proto.NewGreeterClient(conn)

	//md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
	md := metadata.New(map[string]string{
		"name":    "bobby",
		"pasword": "imooc",
	})
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	rsp, err := c.SayHello(ctx, &proto.Person{
		Id:     1000,
		Email:  "bobby@chengpeng.com",
		Mobile: "18888888888",
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(rsp.Id)
}

grpc状态码

https://github.com/grpc/grpc/blob/master/doc/statuscodes.md

在实际开发中,很多时候我们会自己定义状态码
服务器

st := status.New(codes.InvalidArgument, "invalid username")
或者
尽量使用这种方法
status.Error(codes.InvalidArgument, "invalid username")

客户端

st, ok := status.FromError(err)
if !ok {
 // Error was not a status error
}
st.Message()
st.Code()

grpc的超时机制–>grpc的超时机制比较简单

1:网络抖动
2:网络拥塞
3:服务器很慢

ctx, _ := context.WithTimeout(context.Background(), time.Second*3)

在这里插入图片描述

yapi安装

git clone https://github.com/Ryan-Miao/docker-yapi.git
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值