今天我来讲一讲 gRPC 元数据的使用,以及如何获取元数据。 gRPC 应用程序通常会通过 gRPC 服务和消费者之间的 RPC 来共享信息。在大多数场景中,某些与服务端业务逻辑相关的信息会作为远程调用方法的参数,但在某些场景可能存在与服务端业务上下文无关的数据,这些数据不应该通过参数来传递,而应该通过 gRPC 元数据来处理传递。元数据的结构构造是K-V 形式,其中 k 为字符串,v 为任意类型。

接下来就介绍如何在 客户端和服务端之间使用元数据来传递数据。

创建和查询元数据

在 gRPC 应用程序中, 创建元数据非常简单,在 go 语言中有两种方式创建元数据:1) 通过 metadata.New(map[string]string{“key1”:“val1”}) 函数创建;2) 通过 metadata.Pairs 来创建元数据对,相同的 key 会被合并为切片数组。

1
2
3
4
5
    md := metadata.New(map[string]string{"foo": "bar"})
md := metadata.Pairs(
"key1", "value1",
"key2", "value2",
)

二进制数据也可以设置为元数据值,以元数据值形式所设置的二进制数据在发送前都会进行 base4 编码,在传输过程中会被解码。

在客户端或服务端读取元数据,可以通过传入的 RPC 上下文和 metadata.FromIncomingContext 函数来获取元数据。

1
    md, metadataAvailble := metadata.FromIncomingContext(ctx)

接下来讲解客户端和服务端如何发送和接受元数据。

客户端发送接收元数据

在客户端,要发送元数据,可以创建元数据并将其设置到 RPC 上下文中。在 go 语言中有两种方式实现, 可以使用 NewOutgoingContext 函数创建,也可以使用 AppendToOutgoingContext 函数来将元数据附加到 RPC 上下文中, 使用 NewOutgoingContext 会替换掉上下文中已有的元数据。 在创建完带有元数据的上下文后,就可以用于 RPC 中了。在上下文中设置的元数据会转换成 header 信息。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 客户端发送元数据
// ****** Metadata : Creation *****

    md := metadata.Pairs(
    "timestamp", time.Now().Format(time.StampNano),
    "kn", "vn",
    )
    mdCtx := metadata.NewOutgoingContext(context.Background(), md)

    ctxA := metadata.AppendToOutgoingContext(mdCtx, "k1", "v1", "k1", "v2", "k2", "v3")

    // Search Order
    searchStream, _ := client.SearchOrders(ctxA, &wrapper.StringValue{Value: "Google"})
    for {
        searchOrder, err := searchStream.Recv()
        if err == io.EOF {
            log.Print("EOF")
            break
        }

        if err == nil {
            log.Print("Search Result : ", searchOrder)
        }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 在 gRPC 中接受元数据
    var header,trailer metadata.MD
   r,err := client.SomeRPC(
	   ctx,
	   someReq,
	   grpc.Header(&header),
	   grpc.Trailer(trailer),
    )
   stream, err := client.SomeStreamingRPC(ctx)
   
   header, err := stream.Header()
   
   trailer := stream.Trailer()

从对应的 RPC 获取到值时,就可以像处理map一样进行,对元数据进行相应处理。

服务端接收和发送元数据

在服务端接收元数据非常简单,只需在方法调用方法 metadata.FromIncomingContext(ctx),即可读取元数据。

要从服务端发送元数据,可以根据元数据发送头信息或设置 trailer,创建元数据的方法跟前面一样。在一元RPC 和流 RPC 都可以通过 grpc.SendHeader 发送元数据,如果想要将元数据作为 trailer 的一部分发送,则需要使用 grpc.SetTrailer方法设置。

小结

本完先是介绍了如何创建和查询元数据,后面分别简单介绍了 客户端和服务端如何发送和接收元数据。