在服务器端如何读取 gRPC 中的元数据?(使用 Golang 示例)

huangapple go评论85阅读模式
英文:

how to read metadata in grpc on the server side? (golang example)

问题

在gRPC的服务器端如何读取作为头部传递的元数据?有没有使用golang的示例?

我正在编写类似以下的代码:

// 这应该从客户端作为上下文传递,并需要在服务器端访问以读取元数据
var headers = metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})

我想将授权令牌传递给我的验证函数,以验证接收到的令牌。

func validate_token(ctx context.Context, md *metadata.MD) (context.Context, error){
token := headers["authorization"]
}

英文:

How to read metadata (passed as a header) on the server side in grpc? Any example in golang?

I am writing something like this:

// this should be passed from the client side as a context and needs to accessed on server side to read the metadata
var headers = metadata.New(map[string]string{"authorization": "", "space":  "", "org": "", "limit": "", "offset": ""})

I want to pass the Authorization token to my validation function to validate the received token.

func validate_token(ctx context.Context, md *metadata.MD) (context.Context, error){
    token := headers["authorization"]
}

答案1

得分: 40

在调用服务器之前,您需要将元数据插入客户端的上下文中。

对于一元RPC,客户端代码如下:

conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // 使用grpc protoc选项从您的proto生成

header := metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})
// 这是包含您的标头的关键步骤
ctx := metadata.NewContext(context.Background(), header)

request := // 构造您的服务的请求
response, err := client.MyMethod(ctx, request)

对于流式传输,代码几乎相同:

conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // 使用grpc protoc选项从您的proto生成

header := metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})
// 这是包含您的标头的关键步骤
ctx := metadata.NewContext(context.Background(), header)
stream, err := client.MyMethodStream(ctx)

for {
    request :=  // 构造您的服务的请求
    err := stream.Send(request)
    response := new(Response)
    err = stream.RecvMsg(response)
}

对于一元RPC的服务器端代码:

func (s myServer) MyMethod(context.Context, *Request) (*Response, error) {
    md, ok := metadata.FromIncomingContext(ctx)
    token := md.Get("authorization")[0] // metadata.Get返回键的值数组
}

对于流式RPC:

func (s myServer) MyMethodStream(stream MyMethod_MyServiceStreamServer) error {
    md, ok := metadata.FromIncomingContext(stream.Context())
    token := md.Get("authorization")[0] // metadata.Get返回键的值数组
    for {
        request := new(Request)
        err := stream.RecvMsg(request)
        response := // 处理工作
        err := stream.SendMsg(response)
    }
}

请注意,对于流式传输,只有三种情况可以发送标头:在用于打开初始流的上下文中,通过grpc.SendHeadergrpc.SetTrailer。无法在流中的任意消息上设置标头。对于一元RPC,标头将与每个消息一起发送,并且可以在初始上下文中、使用grpc.SendHeader和grpc.SetHeader以及grpc.SetTrailer中设置。

英文:

You have to insert your metadata into the client's context before calling the server.

For an unary RPC the client side looks like:

conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // generated from your proto with the grpc protoc option

header := metadata.New(map[string]string{"authorization": "", "space":  "", "org": "", "limit": "", "offset": ""})
// this is the critical step that includes your headers
ctx := metadata.NewContext(context.Background(), header)

request := // construct a request for your service
response, err := client.MyMethod(ctx, request)

For a stream, it looks almost the same:

conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // generated from your proto with the grpc protoc option

header := metadata.New(map[string]string{"authorization": "", "space":  "", "org": "", "limit": "", "offset": ""})
// this is the critical step that includes your headers
ctx := metadata.NewContext(context.Background(), header)
stream, err := client.MyMethodStream(ctx)

for {
    request :=  // construct a request for your service
    err := stream.Send(request)
    response := new(Response)
    err = stream.RecvMsg(response)
}

On the server side for an unary RPC:

func (s myServer) MyMethod(context.Context, *Request) (*Response, error) {
    md, ok := metadata.FromIncomingContext(ctx)
    token := md.Get("authorization")[0] // metadata.Get returns an array of values for the key
}

and for a streaming RPC:

func (s myServer) MyMethodStream(stream MyMethod_MyServiceStreamServer) error {
    md, ok := metadata.FromIncomingContext(stream.Context())
    token := md.Get("authorization")[0] // metadata.Get returns an array of values for the key
    for {
        request := new(Request)
        err := stream.RecvMsg(request)
        response := // do work
        err := stream.SendMsg(response)
    }
}

Note that for a stream there are only three times that headers can be sent: in the context used to open the initial stream, via grpc.SendHeader, and grpc.SetTrailer. It is not possible to set headers on arbitrary messages in a stream. For an unary RPC header are sent with every message and can be set in the initial context, with grpc.SendHeader and grpc.SetHeader, and grpc.SetTrailer.

答案2

得分: 7

原始答案是正确的,但读取标头的方法已经过时。

import "google.golang.org/grpc/metadata"

func (s myServer) MyMethod(ctx context.Context, *Request) (*Response, error) {
  var values []string
  var token string

  md, ok := metadata.FromIncomingContext(ctx)
  if ok {
    values = md.Get("authorization")
  }

  if len(values) > 0 {
    token = values[0]
  }

  // 使用 token 做一些操作
}
英文:

original answer is correct but reading the headers is slightly outdated

import "google.golang.org/grpc/metadata"

func (s myServer) MyMethod(ctx context.Context, *Request) (*Response, error) {
  var values []string
  var token string

  md, ok := metadata.FromIncomingContext(ctx)
  if ok {
    values = md.Get("authorization")
  }

  if len(values) > 0 {
    token = values[0]
  }

  // do something with token
}

huangapple
  • 本文由 发表于 2017年2月8日 23:04:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/42116642.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定