go控制gRPC的metadata

wxvirus2023年1月24日
大约 1 分钟

go 控制 gRPC 的 metadata

gRPC 让我们可以像本地调用一样实现远程调用,对于每一次的 RPC 调用中,都可能会有一些有用的数据,而这些数据就可以通过metadata来传递。metadata是以key-value的形式存储数据的,其中keystring类型,而value[]stringmetadata使得clientserver能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeaderResponseHeader一样。httpheader的生命周期是一次http请求,那么metadata的生命周期就是一次RPC调用。

go 中使用 metadata

  1. 新建metadata

    type MD map[string][]string
    

    类型是map,keystringvaluestring类型的切片

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

    // 第一种方式
    md := metadata.New(map[string]string{"key1": "val1"})
    
    // 第二种方式
    md := metadata.Pairs (
        "key1", "val1",
        "key2", "val2"
    )
    
  2. 发送metadata

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

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

gRPC 中使用metadata

客户端

package main

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
	"grpcandprotobuf/pb"
	"log"
	"time"
)

func main() {
	conn, err := grpc.Dial("127.0.0.1:8080", grpc.WithInsecure())
	if err != nil {
		log.Fatalln(err)
	}
	defer func(conn *grpc.ClientConn) {
		err := conn.Close()
		if err != nil {
			log.Fatalln(err)
		}
	}(conn)

	c := pb.NewGreeterClient(conn)

	md := metadata.New(map[string]string{
		"name": "wujie",
		"password": "123456",
	})

	ctx := metadata.NewOutgoingContext(context.Background(), md)

	r, err := c.SayHello(ctx, &pb.HelloRequest{
		Name: "wujie",
		Url:  "https",
		G:    pb.Gender_MALE,
		Mp: map[string]string{
			"name":    "wujie",
			"company": "无解的游戏",
		},
		AddTime: timestamppb.New(time.Now()),
	})
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(r.Message)
}

服务端的代码

func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply, error) {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		fmt.Println("get metadata error")
	}
	for key, val := range md {
		fmt.Println(key, val)
	}
	return &proto.HelloReply{Message: "hello " + request.Name}, nil
}
Loading...