使用 Spring Boot WebClient 时如何拦截请求
Posted
技术标签:
【中文标题】使用 Spring Boot WebClient 时如何拦截请求【英文标题】:How to intercept a request when using SpringBoot WebClient 【发布时间】:2019-01-14 13:16:57 【问题描述】:我正在尝试使用WebClient
来调用我的restServices。以前在RestTemplate
上,我们定义了ClientHttpRequestInterceptor
并将其附加到RestTemplate
以拦截和修改请求。使用WebClient
,有没有办法做到这一点?
谢谢,
-Sreeni
【问题讨论】:
【参考方案1】:当您使用 WebClient Builder 时,您可以使用 filter()
方法传入 ExchangeFilterFunction
接口的实现。这相当于ClientHttpRequestInterceptor
的RestTemplate
。
WebClient 构建器文档: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);
;
【讨论】:
我知道这在某种意义上可能相当于ClientHttpRequestInterceptor,但它并没有给你太多的访问权限。例如,您看不到请求的正文。【参考方案2】:在我的情况下,我需要从传入请求中获取一些标头并将它们放入我的请求中。我找到了我需要的东西here。
首先需要一个过滤器
/**
* 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));
还有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));
最后像 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);
);
【讨论】:
【参考方案3】:您可以使用 ExchangeFilterFunction
并在您正在使用的 WebClient
实例上配置它。有关更多信息,请参阅Spring Framework reference documentation。
【讨论】:
以上是关于使用 Spring Boot WebClient 时如何拦截请求的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot:如何使用 WebClient 而不是 RestTemplate 来执行非阻塞和异步调用
使用 Spring Boot webclient 反序列化 OffsetDateTime