WebClient的ExchangeFilterFunction中RequestContextHolder的用法

问题描述

背景:我有传统的Spring MVC应用程序(Spring Boot),该应用程序利用Spring Cloud OpenFeign(REST服务使用)和Apache CXF(SOAP服务使用)。我试图查看是否可以将这两个HTTP客户端整合到Spring的WebClient中。


我试图找出是否有更好的方法来引用放置在RequestContextHolder中的属性,然后在ExchangeFilterFunction中使用/使用它们(代替各种Feign / CXF请求拦截器)。 / p>

例如,以下工作原理:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;

import java.util.HashMap;
import java.util.Map;

import static java.util.Objects.requireNonNull;
@SpringBootApplication
public class DemoApplication {

    private static Log logger = LogFactory.getLog(DemoApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class,args);
    }

    @Bean
    RouterFunction<ServerResponse> router(WebClient.Builder webClientBuilder) {
        WebClient webClient = webClientBuilder.baseUrl("https://jsonplaceholder.typicode.com").filter((req,next) -> {
            Object foo = requireNonNull(RequestContextHolder.getRequestAttributes()).getAttribute("foo",WebRequest.ScopE_REQUEST);
            logger.info("Foo=" + foo);
            return next.exchange(ClientRequest.from(req).header("foo",foo.toString()).build());
        }).build();

        return RouterFunctions.route()
                .before((request) -> {
                    logger.info("Setting foo from " + Thread.currentThread().getName());
                    RequestContextHolder.getRequestAttributes().setAttribute("foo","bar",WebRequest.ScopE_REQUEST);
                    return ServerRequest.from(request).build();
                })
                .GET("/test",(request) -> {
                    ClientResponse response = webClient.get().uri("/todos/1").exchange().block();

                    Map<String,Object> body = new HashMap<>();
                    body.put("attributes",RequestContextHolder.getRequestAttributes().getAttributeNames(WebRequest.ScopE_REQUEST));
                    body.put("todo",response.bodyToMono(new ParameterizedTypeReference<Map<String,Object>>() {}).block());

                    return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(body);
                })
                .build();
    }
}

请注意,上面仍然是一个servlet /阻塞应用程序示例。唯一的反应部分是WebClientExchangeFilterFunctionRestTemplate处于维护模式,建议根​​据the javadoc使用WebClient

当我向多个端点发送垃圾邮件时,它似乎可以正常工作:

2020-08-24 21:26:22.829  INFO 15212 --- [nio-8080-exec-1] com.example.demo.DemoApplication         : Setting foo from http-nio-8080-exec-1
2020-08-24 21:26:22.829  INFO 15212 --- [nio-8080-exec-1] com.example.demo.DemoApplication         : Foo=bar
2020-08-24 21:26:22.915  INFO 15212 --- [nio-8080-exec-2] com.example.demo.DemoApplication         : Setting foo from http-nio-8080-exec-2
2020-08-24 21:26:22.916  INFO 15212 --- [nio-8080-exec-2] com.example.demo.DemoApplication         : Foo=bar
2020-08-24 21:26:23.011  INFO 15212 --- [nio-8080-exec-3] com.example.demo.DemoApplication         : Setting foo from http-nio-8080-exec-3
2020-08-24 21:26:23.011  INFO 15212 --- [nio-8080-exec-3] com.example.demo.DemoApplication         : Foo=bar
2020-08-24 21:26:23.118  INFO 15212 --- [nio-8080-exec-4] com.example.demo.DemoApplication         : Setting foo from http-nio-8080-exec-4
2020-08-24 21:26:23.119  INFO 15212 --- [nio-8080-exec-4] com.example.demo.DemoApplication         : Foo=bar

但是,由于Reactor提供了Context,而且这样做this Reactor FAQ明确地指出了以下内容(强调我的意思),因此这样做是错误的:

现在,我们已经确定MDC “正常工作”并不是在声明性API中做出的最佳假设

感谢任何帮助/指导。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)