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

1. go中使用metadata

源码:源码
项目文档:文档

1. 新建metadata

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

  1. type MD map[string][]string

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

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

2. 发送metadata

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

3. 接收metadata

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

2. grpc中使用metadata

1. proto

  1. syntax = "proto3";
  2. option go_package=".;proto";
  3. // The greeting service definition.
  4. service Greeter {
  5. // Sends a greeting
  6. rpc SayHello (HelloRequest) returns (HelloReply) {
  7. }
  8. }
  9. // The request message containing the user's name.
  10. message HelloRequest {
  11. string name = 1;
  12. }
  13. // The response message containing the greetings
  14. message HelloReply {
  15. string message = 1;
  16. }

2. client

  1. package main
  2. import (
  3. "OldPackageTest/grpc_test/proto"
  4. "context"
  5. "fmt"
  6. "google.golang.org/grpc"
  7. "google.golang.org/grpc/metadata"
  8. )
  9. func main(){
  10. //stream
  11. conn, err := grpc.Dial("127.0.0.1:50051", grpc.WithInsecure())
  12. if err != nil {
  13. panic(err)
  14. }
  15. defer conn.Close()
  16. c := proto.NewGreeterClient(conn)
  17. //md := metadata.Pairs("timestamp", time.Now().Format(timestampFormat))
  18. md := metadata.New(map[string]string{
  19. "name":"yeliangchen",
  20. "pasword":"123456",
  21. })
  22. ctx := metadata.NewOutgoingContext(context.Background(), md)
  23. r, err := c.SayHello(ctx, &proto.HelloRequest{Name:"yeliangchen"})
  24. if err != nil {
  25. panic(err)
  26. }
  27. fmt.Println(r.Message)
  28. }

3. server

  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "google.golang.org/grpc/metadata"
  6. "net"
  7. "google.golang.org/grpc"
  8. "OldPackageTest/grpc_test/proto"
  9. )
  10. type Server struct{}
  11. func (s *Server) SayHello(ctx context.Context, request *proto.HelloRequest) (*proto.HelloReply,
  12. error) {
  13. md, ok := metadata.FromIncomingContext(ctx)
  14. if ok {
  15. fmt.Println("get metadata error")
  16. }
  17. if nameSlice, ok := md["name"]; ok {
  18. fmt.Println(nameSlice)
  19. for i, e := range nameSlice {
  20. fmt.Println(i, e)
  21. }
  22. }
  23. return &proto.HelloReply{
  24. Message: "hello " + request.Name,
  25. }, nil
  26. }
  27. func main() {
  28. g := grpc.NewServer()
  29. proto.RegisterGreeterServer(g, &Server{})
  30. lis, err := net.Listen("tcp", "0.0.0.0:50051")
  31. if err != nil {
  32. panic("failed to listen:" + err.Error())
  33. }
  34. err = g.Serve(lis)
  35. if err != nil {
  36. panic("failed to start grpc:" + err.Error())
  37. }
  38. }