You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:16:00