gRPC让我们可以像本地调用一样实现远程调用,对于每一次的RPC调用中,都可能会有一些在header中传递的数据,而这些数据就可以通过metadata来传递。
metadata是以key-value的形式存储数据的,其中key是string类型,value是[]string类型,即一个字符串切片类型。metadata使得client和server能够为对方提供关于本次调用的一些信息,就像一次http请求的RequestHeader和ResponseHeader一样。http中header的生命周期是一次http请求,那么metadata的生命周期就是一次RPC调用。
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"
1)新建metadataMD 类型实际上是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)发送metadatamd := metadata.Pairs("key", "val")// 新建一个有 metadata 的 contextctx := metadata.NewOutgoingContext(context.Background(), md)// 单向 RPCresponse, err := client.SomeRPC(ctx, someRequest)
3)接收metadatafunc (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) { md, ok := metadata.FromIncomingContext(ctx) // do something with metadata}
2.gRPC中使用metadata 1)protosyntax = "proto3";option go_package = "./;proto";service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {}}message HelloRequest { string name = 1;}message HelloReply { string message = 1;}
执行命令编译文件,生成.pb.go文件:protoc -I 、test.proto --go_out=plugins=grpc:.
2)clientpackage mainimport ("context""fmt""go-class/rpc/07metadata/proto""google.golang.org/grpc""google.golang.org/grpc/metadata")func main() {conn, err := grpc.Dial(":8083", grpc.WithInsecure())if err != nil {panic(err)}defer conn.Close()c := proto.NewGreeterClient(conn)//写入metadata***********md := metadata.New(map[string]string{"name": "lff","password": "123456",})ctx := metadata.NewOutgoingContext(context.Background(), md)r, err := c.SayHello(ctx, &proto.HelloRequest{Name: "lff111"})if err != nil {panic(err)}fmt.Println(r.Message)}
3)serverpackage mainimport ("context""fmt""net""google.golang.org/grpc""google.golang.org/grpc/metadata""go-class/rpc/07metadata/proto")type Server struct {}func (s *Server) SayHello(ctx context.Context, req *proto.HelloRequest) (*proto.HelloReply, error) { //获取header*********md, ok := metadata.FromIncomingContext(ctx)if ok {fmt.Println("get metadata error")}for key, val := range md {fmt.Println(key, val)} //获取header中的name*********//if nameSlice, ok := md["name"]; ok {//fmt.Println(nameSlice)//for i, e := range nameSlice {//fmt.Println(i, e)//}//}return &proto.HelloReply{Message: "Hello " + req.Name,}, nil}func main(){g := grpc.NewServer()proto.RegisterGreeterServer(g, &Server{})lis, err := net.Listen("tcp", "127.0.0.1:8083")if err != nil {panic("failed to listen:" + err.Error())}err = g.Serve(lis)if err != nil {panic("failed to start grpc:" + err.Error())}}
先启动server,在启动client端,结果看到打印出的header