首页 > 解决方案 > 如何在拦截器中安全地将值添加到 grpc ServerStream

问题描述

我的 grpc 服务器有一个日志拦截器,并且想为元数据添加一个值(我想在请求的整个生命周期内跟踪请求):

func (m *middleware) loggingInterceptor(srv interface{},
    ss grpc.ServerStream,
    info *grpc.StreamServerInfo,
    handler grpc.StreamHandler) 

    md, ok := metadata.FromIncomingContext(ss.Context())
    if !ok {
        return errors.New("could not get metadata from incoming stream context")
    }

    // add the transaction id to the metadata so that business logic can track it
    md.Append("trans-id", "some-transaction-id")

    // call the handler func
    return handler(srv, ss)
}

但文档FromIncomingContext声明:

// FromIncomingContext returns the incoming metadata in ctx if it exists.  The
// returned MD should not be modified. Writing to it may cause races.
// Modification should be made to copies of the returned MD.

好的,所以我看一下复制功能并复制元数据:

mdCopy := md.Copy()
mdCopy.Append("trans-id", "some-transaction-id")

并想“我如何将这个元数据附加回ServerStream上下文?”,然后我检查是否有一些ss.SetContext(newCtx),但我没有看到任何类似的东西。我是从错误的角度考虑这个问题,还是我错过了其他东西?

标签: gogrpcgrpc-go

解决方案


您需要使用NewIncomingContext在流中创建当前上下文的副本。

然后,您必须创建一个wrappedStream覆盖Context方法 in的类型ServerStream以返回修改后的context. 您需要将其传递wrappedStreamhandler您在拦截器中收到的。

你可以在这里看到一个例子(它在这里覆盖了其他方法,但想法是一样的): https ://github.com/grpc/grpc-go/blob/master/examples/features/interceptor/server/main .go#L106-L124

希望这可以帮助。


推荐阅读