google.golang.org/grpc@v1.72.2/Documentation/grpc-metadata.md (about) 1 # Metadata 2 3 gRPC supports sending metadata between client and server. 4 This doc shows how to send and receive metadata in gRPC-go. 5 6 ## Background 7 8 Four kinds of service method: 9 10 - [Unary RPC](https://grpc.io/docs/guides/concepts.html#unary-rpc) 11 - [Server streaming RPC](https://grpc.io/docs/guides/concepts.html#server-streaming-rpc) 12 - [Client streaming RPC](https://grpc.io/docs/guides/concepts.html#client-streaming-rpc) 13 - [Bidirectional streaming RPC](https://grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc) 14 15 And concept of [metadata]. 16 17 ## Constructing metadata 18 19 A metadata can be created using package [metadata]. 20 The type MD is actually a map from string to a list of strings: 21 22 ```go 23 type MD map[string][]string 24 ``` 25 26 Metadata can be read like a normal map. 27 Note that the value type of this map is `[]string`, 28 so that users can attach multiple values using a single key. 29 30 ### Creating a new metadata 31 32 A metadata can be created from a `map[string]string` using function `New`: 33 34 ```go 35 md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"}) 36 ``` 37 38 Another way is to use `Pairs`. 39 Values with the same key will be merged into a list: 40 41 ```go 42 md := metadata.Pairs( 43 "key1", "val1", 44 "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"} 45 "key2", "val2", 46 ) 47 ``` 48 49 __Note:__ all the keys will be automatically converted to lowercase, 50 so "key1" and "kEy1" will be the same key and their values will be merged into the same list. 51 This happens for both `New` and `Pairs`. 52 53 ### Storing binary data in metadata 54 55 In metadata, keys are always strings. But values can be strings or binary data. 56 To store binary data value in metadata, simply add "-bin" suffix to the key. 57 The values with "-bin" suffixed keys will be encoded when creating the metadata: 58 59 ```go 60 md := metadata.Pairs( 61 "key", "string value", 62 "key-bin", string([]byte{96, 102}), // this binary data will be encoded (base64) before sending 63 // and will be decoded after being transferred. 64 ) 65 ``` 66 67 ## Sending and receiving metadata - client side 68 69 Client side metadata sending and receiving examples are available 70 [here](../examples/features/metadata/client/main.go). 71 72 ### Sending metadata 73 74 There are two ways to send metadata to the server. The recommended way is to append kv pairs to the context using 75 `AppendToOutgoingContext`. This can be used with or without existing metadata on the context. When there is no prior 76 metadata, metadata is added; when metadata already exists on the context, kv pairs are merged in. 77 78 ```go 79 // create a new context with some metadata 80 ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3") 81 82 // later, add some more metadata to the context (e.g. in an interceptor) 83 ctx := metadata.AppendToOutgoingContext(ctx, "k3", "v4") 84 85 // make unary RPC 86 response, err := client.SomeRPC(ctx, someRequest) 87 88 // or make streaming RPC 89 stream, err := client.SomeStreamingRPC(ctx) 90 ``` 91 92 Alternatively, metadata may be attached to the context using `NewOutgoingContext`. However, this 93 replaces any existing metadata in the context, so care must be taken to preserve the existing 94 metadata if desired. This is slower than using `AppendToOutgoingContext`. An example of this 95 is below: 96 97 ```go 98 // create a new context with some metadata 99 md := metadata.Pairs("k1", "v1", "k1", "v2", "k2", "v3") 100 ctx := metadata.NewOutgoingContext(context.Background(), md) 101 102 // later, add some more metadata to the context (e.g. in an interceptor) 103 send, _ := metadata.FromOutgoingContext(ctx) 104 newMD := metadata.Pairs("k3", "v3") 105 ctx = metadata.NewOutgoingContext(ctx, metadata.Join(send, newMD)) 106 107 // make unary RPC 108 response, err := client.SomeRPC(ctx, someRequest) 109 110 // or make streaming RPC 111 stream, err := client.SomeStreamingRPC(ctx) 112 ``` 113 114 ### Receiving metadata 115 116 Metadata that a client can receive includes header and trailer. 117 118 #### Unary call 119 120 Header and trailer sent along with a unary call can be retrieved using function 121 [Header] and [Trailer] in [CallOption]: 122 123 ```go 124 var header, trailer metadata.MD // variable to store header and trailer 125 r, err := client.SomeRPC( 126 ctx, 127 someRequest, 128 grpc.Header(&header), // will retrieve header 129 grpc.Trailer(&trailer), // will retrieve trailer 130 ) 131 132 // do something with header and trailer 133 ``` 134 135 #### Streaming call 136 137 For streaming calls including: 138 139 - Server streaming RPC 140 - Client streaming RPC 141 - Bidirectional streaming RPC 142 143 Header and trailer can be retrieved from the returned stream using function 144 `Header` and `Trailer` in interface [ClientStream]: 145 146 ```go 147 stream, err := client.SomeStreamingRPC(ctx) 148 149 // retrieve header 150 header, err := stream.Header() 151 152 // retrieve trailer 153 trailer := stream.Trailer() 154 155 ``` 156 157 ## Sending and receiving metadata - server side 158 159 Server side metadata sending and receiving examples are available 160 [here](../examples/features/metadata/server/main.go). 161 162 ### Receiving metadata 163 164 To read metadata sent by the client, the server needs to retrieve it from RPC 165 context using [FromIncomingContext]. 166 If it is a unary call, the RPC handler's context can be used. 167 For streaming calls, the server needs to get context from the stream. 168 169 #### Unary call 170 171 ```go 172 func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) { 173 md, ok := metadata.FromIncomingContext(ctx) 174 // do something with metadata 175 } 176 ``` 177 178 #### Streaming call 179 180 ```go 181 func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error { 182 md, ok := metadata.FromIncomingContext(stream.Context()) // get context from stream 183 // do something with metadata 184 } 185 ``` 186 187 ### Sending metadata 188 189 #### Unary call 190 191 To send header and trailer to client in unary call, the server can call 192 [SetHeader] and [SetTrailer] functions in module [grpc]. 193 These two functions take a context as the first parameter. 194 It should be the RPC handler's context or one derived from it: 195 196 ```go 197 func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) { 198 // create and set header 199 header := metadata.Pairs("header-key", "val") 200 grpc.SetHeader(ctx, header) 201 // create and set trailer 202 trailer := metadata.Pairs("trailer-key", "val") 203 grpc.SetTrailer(ctx, trailer) 204 } 205 ``` 206 207 #### Streaming call 208 209 For streaming calls, header and trailer can be sent using function 210 [SetHeader] and [SetTrailer] in interface [ServerStream]: 211 212 ```go 213 func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error { 214 // create and set header 215 header := metadata.Pairs("header-key", "val") 216 stream.SetHeader(header) 217 // create and set trailer 218 trailer := metadata.Pairs("trailer-key", "val") 219 stream.SetTrailer(trailer) 220 } 221 ``` 222 223 **Important** 224 225 Do not use 226 [FromOutgoingContext] on the server to write metadata to be sent to the client. 227 [FromOutgoingContext] is for client-side use only. 228 229 ## Updating metadata from a server interceptor 230 231 An example for updating metadata from a server interceptor is 232 available [here](../examples/features/metadata_interceptor/server/main.go). 233 234 [FromIncomingContext]: <https://pkg.go.dev/google.golang.org/grpc/metadata#FromIncomingContext> 235 [SetHeader]: <https://godoc.org/google.golang.org/grpc#SetHeader> 236 [SetTrailer]: https://godoc.org/google.golang.org/grpc#SetTrailer 237 [FromOutgoingContext]: https://pkg.go.dev/google.golang.org/grpc/metadata#FromOutgoingContext 238 [ServerStream]: https://godoc.org/google.golang.org/grpc#ServerStream 239 [grpc]: https://godoc.org/google.golang.org/grpc 240 [ClientStream]: https://godoc.org/google.golang.org/grpc#ClientStream 241 [Header]: https://godoc.org/google.golang.org/grpc#Header 242 [Trailer]: https://godoc.org/google.golang.org/grpc#Trailer 243 [CallOption]: https://godoc.org/google.golang.org/grpc#CallOption 244 [metadata]: https://godoc.org/google.golang.org/grpc/metadata