如何在ReactiveFeignClient的响应式切面中获取请求头?
在Reactive Feign切面中获取请求头的实现方案
响应式环境下不能使用基于ThreadLocal的RequestContextHolder(非响应式方案),因为响应式线程模型是非阻塞、线程复用的,ThreadLocal无法正确绑定请求上下文。以下是几种可行的实现方式:
方式一:从Feign方法参数中直接提取
如果你的Reactive Feign接口方法中声明了HttpHeaders参数,或者通过@RequestHeader注解传递了头信息,可以直接从切面的ProceedingJoinPoint中获取参数:
示例Feign接口
@ReactiveFeignClient(name = "target-service") interface TargetClient { @GetMapping("/api/data") suspend fun fetchData(@RequestHeader headers: HttpHeaders): DataResponse }
切面中获取请求头
@Around("@within(reactivefeign.spring.config.ReactiveFeignClient)") suspend fun handle(pjp: ProceedingJoinPoint) = withTraceContext { // 从方法参数中筛选HttpHeaders对象 val requestHeaders = pjp.args.firstOrNull { it is HttpHeaders } as? HttpHeaders requestHeaders?.let { // 示例:打印Authorization头 println("Authorization: ${it.getFirst(HttpHeaders.AUTHORIZATION)}") } pjp.proceed() }
方式二:通过Reactor Context传递并获取
如果请求头是在调用Feign客户端前放入Reactor Context的,可在切面中直接读取当前上下文:
调用Feign时注入请求头到Context
// 假设当前已有请求头对象currentHeaders mono.deferContextual { ctx -> targetClient.fetchData() }.contextWrite { it.put("REQUEST_HEADERS", currentHeaders) }
切面中读取Context里的请求头
@Around("@within(reactivefeign.spring.config.ReactiveFeignClient)") suspend fun handle(pjp: ProceedingJoinPoint) = withTraceContext { // 获取当前Reactor Context val reactorContext = ReactorContextAccessor.currentContext() // 从Context中取出请求头,默认空HttpHeaders val requestHeaders = reactorContext.getOrDefault<HttpHeaders>("REQUEST_HEADERS", HttpHeaders.EMPTY) // 示例:打印X-Request-ID头 println("X-Request-ID: ${requestHeaders.getFirst("X-Request-ID")}") pjp.proceed() }
方式三:解析Reactive Feign的请求对象
Reactive Feign的方法调用参数中通常会包含ReactiveHttpRequest对象,该对象封装了完整的请求信息(包括头):
@Around("@within(reactivefeign.spring.config.ReactiveFeignClient)") suspend fun handle(pjp: ProceedingJoinPoint) = withTraceContext { // 从参数中筛选ReactiveHttpRequest对象 val reactiveRequest = pjp.args.firstOrNull { it is ReactiveHttpRequest } as? ReactiveHttpRequest reactiveRequest?.let { val requestHeaders = it.headers() // 示例:打印User-Agent头 println("User-Agent: ${requestHeaders.getFirst(HttpHeaders.USER_AGENT)}") } pjp.proceed() }
额外说明(Spring WebFlux场景)
如果是在Spring WebFlux环境中,可通过WebFilter将当前请求的ServerWebExchange注入Reactor Context,再在切面中获取请求头:
自定义WebFilter注入上下文
@Component class WebExchangeContextFilter : WebFilter { override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> { return chain.filter(exchange) .contextWrite { it.put(ServerWebExchange::class.java, exchange) } } }
切面中获取WebExchange里的请求头
@Around("@within(reactivefeign.spring.config.ReactiveFeignClient)") suspend fun handle(pjp: ProceedingJoinPoint) = withTraceContext { val reactorContext = ReactorContextAccessor.currentContext() val exchange = reactorContext.get<ServerWebExchange>(ServerWebExchange::class.java) val requestHeaders = exchange.request.headers // 处理请求头逻辑 pjp.proceed() }
内容的提问来源于stack exchange,提问作者Fairy
相关产品推荐
相关产品推荐

