Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

5 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. # Metadata
  2. gRPC supports sending metadata between client and server.
  3. This doc shows how to send and receive metadata in gRPC-go.
  4. ## Background
  5. Four kinds of service method:
  6. - [Unary RPC](https://grpc.io/docs/guides/concepts.html#unary-rpc)
  7. - [Server streaming RPC](https://grpc.io/docs/guides/concepts.html#server-streaming-rpc)
  8. - [Client streaming RPC](https://grpc.io/docs/guides/concepts.html#client-streaming-rpc)
  9. - [Bidirectional streaming RPC](https://grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc)
  10. And concept of [metadata](https://grpc.io/docs/guides/concepts.html#metadata).
  11. ## Constructing metadata
  12. A metadata can be created using package [metadata](https://godoc.org/google.golang.org/grpc/metadata).
  13. The type MD is actually a map from string to a list of strings:
  14. ```go
  15. type MD map[string][]string
  16. ```
  17. Metadata can be read like a normal map.
  18. Note that the value type of this map is `[]string`,
  19. so that users can attach multiple values using a single key.
  20. ### Creating a new metadata
  21. A metadata can be created from a `map[string]string` using function `New`:
  22. ```go
  23. md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
  24. ```
  25. Another way is to use `Pairs`.
  26. Values with the same key will be merged into a list:
  27. ```go
  28. md := metadata.Pairs(
  29. "key1", "val1",
  30. "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
  31. "key2", "val2",
  32. )
  33. ```
  34. __Note:__ all the keys will be automatically converted to lowercase,
  35. so "key1" and "kEy1" will be the same key and their values will be merged into the same list.
  36. This happens for both `New` and `Pairs`.
  37. ### Storing binary data in metadata
  38. In metadata, keys are always strings. But values can be strings or binary data.
  39. To store binary data value in metadata, simply add "-bin" suffix to the key.
  40. The values with "-bin" suffixed keys will be encoded when creating the metadata:
  41. ```go
  42. md := metadata.Pairs(
  43. "key", "string value",
  44. "key-bin", string([]byte{96, 102}), // this binary data will be encoded (base64) before sending
  45. // and will be decoded after being transferred.
  46. )
  47. ```
  48. ## Retrieving metadata from context
  49. Metadata can be retrieved from context using `FromIncomingContext`:
  50. ```go
  51. func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
  52. md, ok := metadata.FromIncomingContext(ctx)
  53. // do something with metadata
  54. }
  55. ```
  56. ## Sending and receiving metadata - client side
  57. Client side metadata sending and receiving examples are available [here](../examples/features/metadata/client/main.go).
  58. ### Sending metadata
  59. There are two ways to send metadata to the server. The recommended way is to append kv pairs to the context using
  60. `AppendToOutgoingContext`. This can be used with or without existing metadata on the context. When there is no prior
  61. metadata, metadata is added; when metadata already exists on the context, kv pairs are merged in.
  62. ```go
  63. // create a new context with some metadata
  64. ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3")
  65. // later, add some more metadata to the context (e.g. in an interceptor)
  66. ctx := metadata.AppendToOutgoingContext(ctx, "k3", "v4")
  67. // make unary RPC
  68. response, err := client.SomeRPC(ctx, someRequest)
  69. // or make streaming RPC
  70. stream, err := client.SomeStreamingRPC(ctx)
  71. ```
  72. Alternatively, metadata may be attached to the context using `NewOutgoingContext`. However, this
  73. replaces any existing metadata in the context, so care must be taken to preserve the existing
  74. metadata if desired. This is slower than using `AppendToOutgoingContext`. An example of this
  75. is below:
  76. ```go
  77. // create a new context with some metadata
  78. md := metadata.Pairs("k1", "v1", "k1", "v2", "k2", "v3")
  79. ctx := metadata.NewOutgoingContext(context.Background(), md)
  80. // later, add some more metadata to the context (e.g. in an interceptor)
  81. md, _ := metadata.FromOutgoingContext(ctx)
  82. newMD := metadata.Pairs("k3", "v3")
  83. ctx = metadata.NewContext(ctx, metadata.Join(metadata.New(send), newMD))
  84. // make unary RPC
  85. response, err := client.SomeRPC(ctx, someRequest)
  86. // or make streaming RPC
  87. stream, err := client.SomeStreamingRPC(ctx)
  88. ```
  89. ### Receiving metadata
  90. Metadata that a client can receive includes header and trailer.
  91. #### Unary call
  92. Header and trailer sent along with a unary call can be retrieved using function [Header](https://godoc.org/google.golang.org/grpc#Header) and [Trailer](https://godoc.org/google.golang.org/grpc#Trailer) in [CallOption](https://godoc.org/google.golang.org/grpc#CallOption):
  93. ```go
  94. var header, trailer metadata.MD // variable to store header and trailer
  95. r, err := client.SomeRPC(
  96. ctx,
  97. someRequest,
  98. grpc.Header(&header), // will retrieve header
  99. grpc.Trailer(&trailer), // will retrieve trailer
  100. )
  101. // do something with header and trailer
  102. ```
  103. #### Streaming call
  104. For streaming calls including:
  105. - Server streaming RPC
  106. - Client streaming RPC
  107. - Bidirectional streaming RPC
  108. Header and trailer can be retrieved from the returned stream using function `Header` and `Trailer` in interface [ClientStream](https://godoc.org/google.golang.org/grpc#ClientStream):
  109. ```go
  110. stream, err := client.SomeStreamingRPC(ctx)
  111. // retrieve header
  112. header, err := stream.Header()
  113. // retrieve trailer
  114. trailer := stream.Trailer()
  115. ```
  116. ## Sending and receiving metadata - server side
  117. Server side metadata sending and receiving examples are available [here](../examples/features/metadata/server/main.go).
  118. ### Receiving metadata
  119. To read metadata sent by the client, the server needs to retrieve it from RPC context.
  120. If it is a unary call, the RPC handler's context can be used.
  121. For streaming calls, the server needs to get context from the stream.
  122. #### Unary call
  123. ```go
  124. func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
  125. md, ok := metadata.FromIncomingContext(ctx)
  126. // do something with metadata
  127. }
  128. ```
  129. #### Streaming call
  130. ```go
  131. func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
  132. md, ok := metadata.FromIncomingContext(stream.Context()) // get context from stream
  133. // do something with metadata
  134. }
  135. ```
  136. ### Sending metadata
  137. #### Unary call
  138. To send header and trailer to client in unary call, the server can call [SendHeader](https://godoc.org/google.golang.org/grpc#SendHeader) and [SetTrailer](https://godoc.org/google.golang.org/grpc#SetTrailer) functions in module [grpc](https://godoc.org/google.golang.org/grpc).
  139. These two functions take a context as the first parameter.
  140. It should be the RPC handler's context or one derived from it:
  141. ```go
  142. func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
  143. // create and send header
  144. header := metadata.Pairs("header-key", "val")
  145. grpc.SendHeader(ctx, header)
  146. // create and set trailer
  147. trailer := metadata.Pairs("trailer-key", "val")
  148. grpc.SetTrailer(ctx, trailer)
  149. }
  150. ```
  151. #### Streaming call
  152. For streaming calls, header and trailer can be sent using function `SendHeader` and `SetTrailer` in interface [ServerStream](https://godoc.org/google.golang.org/grpc#ServerStream):
  153. ```go
  154. func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
  155. // create and send header
  156. header := metadata.Pairs("header-key", "val")
  157. stream.SendHeader(header)
  158. // create and set trailer
  159. trailer := metadata.Pairs("trailer-key", "val")
  160. stream.SetTrailer(trailer)
  161. }
  162. ```