在Spring boot webflux 中实现 RequestContextHolder,主要目的是为了feign在调用服务时,先获取当前request,然后获取request的header,然后复制给RequestTemplate,进一步传递到服务,给被调用的服务使用。
为什么要像下面这样整这么麻烦,因为RequestContextHolder
.
getRequestAttributes
(
)在webflux
不能用了
具体代码如下:
定义一个filter,把当前请求放入到上下文
package cn.nezhacloud.fireTippedSpear.gateway.filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
@Configuration
public class ReactiveRequestContextFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
return webFilterChain.filter(serverWebExchange).subscriberContext((c) -> c.hasKey(ReactiveRequestContextHolder.CONTEXT_KEY) ? c : this.withContext(c, serverWebExchange));
private Context withContext(Context mainContext, ServerWebExchange exchange) {
return mainContext.putAll(Context.of(ReactiveRequestContextHolder.CONTEXT_KEY,exchange.getRequest()));
再定义一个contextHolder
package cn.nezhacloud.fireTippedSpear.gateway.filter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
import java.util.function.Function;
public class ReactiveRequestContextHolder {
public static final String CONTEXT_KEY = "ServerHttpRequest";
public ReactiveRequestContextHolder() {
public static Mono<ServerHttpRequest> getContext() {
return Mono.subscriberContext().filter((c) -> {
return c.hasKey(CONTEXT_KEY);
}).flatMap((c) -> {
return (Mono)c.get(CONTEXT_KEY);
public static Function<Context, Context> clearContext() {
return (context) -> {
return context.delete(CONTEXT_KEY);
定义feign调用的RequestInterceptor
package cn.nezhacloud.fireTippedSpear.gateway.config;
import cn.nezhacloud.fireTippedSpear.gateway.filter.ReactiveRequestContextHolder;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignRequestConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
//ReactiveRequestContextHolder.getContext().block() 得到的值为null
ReactiveRequestContextHolder.getContext().doOnSuccess(request->{
//这一句不会执行
System.out.println("okkkkkkkkk");
第一种方式
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String x'x= request.getHeader("xx");
requestTemplate.header("xx", xx);
}
但是请记住,坏处是在循环调用feign 的时候 header中的值会丢失,好处是一个方法全部通用
第二种方式
使用@RequestHeader 注解直接写在你feign接口中
String xx(@RequestParam("xx") String xx, @RequestHeader("xx") String xx);
这样的方式的坏处就是每个接口需要header值的话都需要写,好处就是header中的值不会丢失, 简单粗暴