什么是metadata
metadata即为元信息,记录k、v键值对,类似于http请求当中的header,常用于RPC请求当中的鉴权、追溯和验签等场景,元数据可以包含认证token、请求标识和监控标签等
metadata的数据类型
type MD map[string][]string
元数据可以像普通map一样读取。注意,这个 map 的值类型是[]string,因此用户可以使用一个键附加多个值。
创建metadata
metadata.Pairs
md := metadata.Pairs(
"x-token", "codepzj-authorization-key",
"X-TOKEN", "codepzj-authorization-key-2",
"req_id", "req_123456",
)
需要注意的是key是大小写不敏感的,x-token和X-TOKEN会被识别为同一个key,最终值为["codepzj-authorization-key", "codepzj-authorization-key-2"]
k、v字符串
在客户端发起调用的时候,以k、v字符串附加到AppendToOutgoingContext之后
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", "codepzj-authorization-key", "req_id", "req_123456")
客户端发送metadata,服务端接收metadata
client
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", "codepzj-authorization-key", "req_id", "req_123456")
resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: *name})
server
// 1. 接受来自客户端的metadata
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Error(codes.Unauthenticated, "metadata missing")
}
log.Printf("md: %+v\n", md)
// 2. 解析metadata
xToken, ok := md["x-token"]
if !ok {
return nil, status.Error(codes.Unauthenticated, "x-token missing")
}
if len(xToken) == 0 {
return nil, status.Error(codes.Unauthenticated, "x-token missing")
}
log.Println("x-token", xToken[0])
服务端发送metadata,客户端接收metadata
server
// 3. 服务端设置metadata, 发送给客户端
header := metadata.Pairs("x-server", "ok")
if err := grpc.SendHeader(ctx, header); err != nil {
log.Println("Failed to set header from SayHello")
}
defer func() {
trailer := metadata.Pairs("x-trailer", "ok")
if err := grpc.SetTrailer(ctx, trailer); err != nil {
log.Println("Failed to set trailer from SayHello")
}
}()
直接grpc.SendHeader & grpc.SetTrailer
client
var header, trailer metadata.MD
resp, err := client.SayHello(ctx, &pb.HelloRequest{Name: *name}, grpc.Header(&header), grpc.Trailer(&trailer))
if err != nil {
log.Fatalf("failed to call SayHello: %v", err)
}
log.Printf("Response: %s", resp.Message)
log.Printf("Header: %s", header)
在发请求前绑定header OR trailer,收到server响应就绑定到header OR trailer上了