Spring boot webflux 里的feign如何动态添加来自request的header?

冥道残月破 发布于 2020/05/18 18:22
阅读 889
收藏 0

在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");
        });

    }

}

 

加载中
0
o
osc_19866765

请问楼主解决了么,我这里报错提示 context is empty。反而测试使用ThreadLocal存储请求会比较顺利,不清楚咋回事

冥道残月破
冥道残月破
没有找到好办法。网上出现的方案试了都不管用
0
小伯恩
小伯恩

第一种方式  

  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中的值不会丢失, 简单粗暴

OSCHINA
登录后可查看更多优质内容
返回顶部
顶部