使用SpringBoot WebClient时如何拦截请求

Sre*_*eni 8 spring-boot spring-webflux

我正在尝试使用WebClient来调用我的 restServices。之前RestTemplate,我们已经ClientHttpRequestInterceptor定义并附加到RestTemplate来拦截和修改请求。有WebClient没有办法做到这一点?

谢谢,

-Sreeni

Jua*_*uan 11

就我而言,我需要从传入请求中获取一些标头并将它们放入我的请求中。我在这里找到我需要的东西。

首先需要一个过滤器

/**
 * ReactiveRequestContextFilter
 *
 * @author L.cm
 */
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class ReactiveRequestContextFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        return chain.filter(exchange)
        .subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request));
    }
}
Run Code Online (Sandbox Code Playgroud)

ReactiveRequestContextHolder

/**
 * ReactiveRequestContextHolder
 *
 * @author L.cm
 */
public class ReactiveRequestContextHolder {
    static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;

    /**
     * Gets the {@code Mono<ServerHttpRequest>} from Reactor {@link Context}
     * @return the {@code Mono<ServerHttpRequest>}
     */
    public static Mono<ServerHttpRequest> getRequest() {
        return Mono.subscriberContext()
            .map(ctx -> ctx.get(CONTEXT_KEY));
    }

}
Run Code Online (Sandbox Code Playgroud)

最后,就像 Michael McFadyen 说的,你需要配置一个ExchangeFilterFunction,在我的例子中,我需要 Auth 和 origin:

private ExchangeFilterFunction headerFilter() {
    return (request, next) -> ReactiveRequestContextHolder.getRequest()
            .flatMap(r -> {
                ClientRequest clientRequest = ClientRequest.from(request)
                        .headers(headers -> {
                            headers.set(HttpHeaders.ORIGIN, r.getHeaders().getFirst(HttpHeaders.ORIGIN));
                            headers.set(HttpHeaders.AUTHORIZATION, r.getHeaders().getFirst(HttpHeaders.AUTHORIZATION));
                        })
                        .build();
                return next.exchange(clientRequest);
            });
}
Run Code Online (Sandbox Code Playgroud)

编辑:在项目的新版本中,Mono.subscriberContext()反应器不存在。必须将其更改为Mono.deferContextual(Mono::just),.subscriberContext(ctx -> ...)并且.contextWrite(ctx -> ...)


Mic*_*yen 9

当您使用 WebClient Builder 时,您可以ExchangeFilterFunction使用该filter()方法传入接口的实现。这相当于ClientHttpRequestInterceptor`RestTemplate。

WebClient Builder 文档:https : //docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.Builder.html#filter-org.springframework。 web.reactive.function.client.ExchangeFilterFunction-

ExchangeFilterFunction 文档:https : //docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/ExchangeFilterFunction.html

例如:

WebClient webClient = WebClient.builder()
        .baseUrl("http://localhost:8080|)
        .filter(logFilter())
        .build();


private ExchangeFilterFunction logFilter() {
    return (clientRequest, next) -> {
        logger.info("External Request to {}", clientRequest.url());
        return next.exchange(clientRequest);
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道这在某种意义上可能相当于 ClientHttpRequestInterceptor,但它并没有给你太多的访问权限。例如,您看不到请求的正文。 (3认同)