Spring WebFlux Kotlin协程:WebFilter处理的请求头如何传递给gRPC ClientInterceptor
解决方案
核心思路是利用Reactor Context在WebFlux请求上下文和gRPC客户端调用上下文之间传递头信息——WebFilter生成拼接后的头字符串并存入Context,gRPC ClientInterceptor从Context中取出值并设置到元数据里,全程无需手动在每个gRPC调用里显式传参。
1. 实现WebFilter生成头字符串并写入Reactor Context
在WebFilter里提取指定请求头,拼接成目标格式,再通过Reactor的contextWrite将字符串存入当前请求的上下文:
@Component class HeaderTransferWebFilter : WebFilter { // 定义需要提取的目标请求头列表 private val targetHeaders = listOf("header-a", "header-b", "header-c") // 定义Context中存储头字符串的Key(建议抽成全局常量) private val GRPC_HEADERS_KEY = "GRPC_TRANSFER_HEADERS" override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { // 拼接目标头字符串:格式为 "headers: header-a=1; header-b=2; header-c=3" val headerStr = targetHeaders .mapNotNull { headerName -> exchange.request.headers.getFirst(headerName)?.let { "$headerName=$it" } } .joinToString("; ") .takeIf { it.isNotEmpty() }?.let { "headers: $it" } // 将头字符串写入Reactor Context,继续执行后续过滤链 return chain.filter(exchange) .contextWrite { ctx -> headerStr?.let { ctx.put(GRPC_HEADERS_KEY, it) } ?: ctx } } }
2. 实现gRPC ClientInterceptor从Context中取头并设置元数据
自定义ClientInterceptor,在gRPC调用启动时,从Reactor Context中取出之前存入的头字符串,添加到gRPC请求的Metadata中:
@Component class GrpcHeaderTransferInterceptor : ClientInterceptor { private val GRPC_HEADERS_KEY = "GRPC_TRANSFER_HEADERS" // 定义gRPC元数据的Key(和下游服务约定好) private val GRPC_METADATA_KEY = Metadata.Key.of("headers", Metadata.ASCII_STRING_MARSHALLER) override fun <ReqT : Any?, RespT : Any?> interceptCall( method: MethodDescriptor<ReqT, RespT>, callOptions: CallOptions, next: Channel ): ClientCall<ReqT, RespT> { return object : ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) { override fun start(responseListener: Listener<RespT>, headers: Metadata) { // 从当前Reactor Context中取出头字符串 val headerStr = ReactorContextHolder.getContext().get<String>(GRPC_HEADERS_KEY) headerStr?.let { // 将字符串设置到gRPC元数据中 headers.put(GRPC_METADATA_KEY, it) } super.start(responseListener, headers) } } } }
3. 配置gRPC客户端启用该Interceptor
把自定义的Interceptor注册到gRPC客户端的全局配置中,确保所有gRPC调用都会自动应用这个拦截逻辑:
@Configuration class GrpcClientConfig { @Bean fun grpcInterceptorConfigurer(interceptor: GrpcHeaderTransferInterceptor): GrpcClientInterceptorConfigurer { return GrpcClientInterceptorConfigurer { registry -> registry.addClientInterceptor(interceptor) } } }
关键注意点
- 确保项目引入了
grpc-reactor依赖,Reactor Context才能正确传递到gRPC调用上下文; - Kotlin协程和Reactor Context自动兼容,使用
coMono/coFlux或直接在协程中调用gRPC客户端时,上下文会自动继承; - 如果不需要传递空的头字符串,可以在WebFilter里判断只有当有目标头存在时才写入Context,避免无效元数据。
内容的提问来源于stack exchange,提问作者Sean Hwang
相关产品推荐
相关产品推荐

