...

Text file src/google.golang.org/grpc/Documentation/grpc-metadata.md

Documentation: google.golang.org/grpc/Documentation

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

View as plain text