grpc传输metadata

grpc 开发进阶 -传递 metadata

metadata作用简介

grpc 支持在 server 端和 client 端发送 metedata,一些验证信息之类的可以放在这个里边
metadata

可以通过 metadata 包来构建

type MD map[string][]string

一个键可以对应多个值
生成 metadata

func New(m map[string]string) MD
func Pairs(kv ...string) MD


md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})

md = metadata.Pairs(
    "key1", "val1",
    "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
    "key2", "val2",
)

key 中大写字母会被转化为小写
grpc- 开头的键为 grpc 内部使用,如果再 metadata 中设置这样的键可能会导致一些错误

存储二进制

metadata 中可以存储二进制数据
key 以 -bin 为后缀,这时,值会在传输前后以 base64 进行编解码

md := metadata.Pairs(
    "key", "string value",
    "key-bin", string([]byte{96, 102}),
)

注意
服务端和客户端接收到的 metadata 如果被修改的话可能会导致 race
通过 Copy() 方法返回的 metadata 可以修改

func (md MD) Copy() MD

客户端

发送 metadata

有两种发送 metadata 到 server 的方法

推荐的方法是使用 AppendToOutgoingContext
如果 metadata 已存在则会合并,不存在则添加

func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context

// create a new context with some metadata
ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3")

// later, add some more metadata to the context (e.g. in an interceptor)
ctx := metadata.AppendToOutgoingContext(ctx, "k3", "v4")

而 NewOutgoingContext 则会覆盖 context 中 已有的 metadata

func NewOutgoingContext(ctx context.Context, md MD) context.Context

// create a new context with some metadata
md := metadata.Pairs("k1", "v1", "k1", "v2", "k2", "v3")
ctx := metadata.NewOutgoingContext(context.Background(), md)

接收

client 和 server 接收 metadata 的方式是不同的,metadata 会被分为 header 和 triler

unary RPC 可以在调用的时候,使用 CallOption Header 和 Trailer 来获取

```go
var header, trailer metadata.MD // variable to store header and trailer
r, err := client.SomeRPC(
    ctx,
    someRequest,
    grpc.Header(&header),    // will retrieve header
    grpc.Trailer(&trailer),  // will retrieve trailer
)

// do something with header and trailer

stream RPC 可以通过 ClientStream 接口的 Header, Trailer 方法来获取

stream, err := client.SomeStreamingRPC(ctx)

// retrieve header
header, err := stream.Header()

// retrieve trailer
trailer := stream.Trailer()

服务端

发送

server 端会把 metadata 分为 header 和 trailer 发送给 client

unary RPC 可以通过 CallOption grpc.SendHeader 和 grpc.SetTriler 来发送 header, trailer metadata

SetTriler 可以被调用多次,并且所有 metadata 会被合并
当 RPC 返回的时候, trailer metadata 会被发送

func SendHeader(ctx context.Context, md metadata.MD) error

func SetTrailer(ctx context.Context, md metadata.MD) error

func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
    // create and send header
    header := metadata.Pairs("header-key", "val")
    grpc.SendHeader(ctx, header)
    // create and set trailer
    trailer := metadata.Pairs("trailer-key", "val")
    grpc.SetTrailer(ctx, trailer)
}

stream RPC 则可以直接使用 ServerStream 接口的方法

func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
    // create and send header
    header := metadata.Pairs("header-key", "val")
    stream.SendHeader(header)
    // create and set trailer
    trailer := metadata.Pairs("trailer-key", "val")
    stream.SetTrailer(trailer)
}

grpc.SendHeader 和 grpc.SetHeader 的区别

SendHeader 最多会被调用一次,提供的metadata会通过 SetHeader 来设置

SetHeader 可以被多次调用,所有的 metadata 都会被合并
当遇到以下行为的时候 metadata 会被发送

grpc.SendHeader 被调用
第一个响应被发送
RPC status 被发送

接收

服务端调用 FromIncomingContext 即可从 context 中接收 client 发送的 metadata

func FromIncomingContext(ctx context.Context) (md MD, ok bool)


func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
    md, ok := metadata.FromIncomingContext(ctx)
    // do something with metadata
}

func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
    md, ok := metadata.FromIncomingContext(stream.Context()) // get context from stream
    // do something with metadata
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值