I am trying to use the WebClient
to call my restServices. Previously on RestTemplate
, we had ClientHttpRequestInterceptor
defined and attached to the RestTemplate
to intercept and modify the requests. With the WebClient
, is there a way to do the same ?
Thanks,
-Sreeni
To work with interceptor, you need to create @Component class that supports it and it should implement the HandlerInterceptor interface. preHandle() method − This is used to perform operations before sending the request to the controller. This method should return true to return the response to the client.
Logging Request and Response with Body HTTP clients have features to log the bodies of requests and responses. Thus, to achieve the goal, we are going to use a log-enabled HTTP client with our WebClient. We can do this by manually setting WebClient. Builder#clientConnector – let's see with Jetty and Netty HTTP clients.
On the other side, WebClient uses an asynchronous, non-blocking solution provided by the Spring Reactive framework. While RestTemplate uses the caller thread for each event (HTTP call), WebClient will create something like a “task” for each event.
When you are using the WebClient Builder you can pass in implementations of the ExchangeFilterFunction
interface using the filter()
method. This is the equivalent of the ClientHttpRequestInterceptor
for RestTemplate
.
WebClient Builder Docs: 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 Docs: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/ExchangeFilterFunction.html
For example:
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);
};
}
In my case i need to get Some headers from incoming requests and put them into my requests. I find what i need here.
First of all a filter is needed
/**
* 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));
}
}
And 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));
}
}
And finally like Michael McFadyen say you need to configure an ExchangeFilterFunction
, in my case i need Auth and 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);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With