Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intercept a request when using SpringBoot WebClient

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

like image 220
Sreeni Avatar asked Aug 07 '18 12:08

Sreeni


People also ask

How do you intercept HTTP requests in Spring boot?

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.

How do I log a body response in WebClient?

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.

Is Spring WebClient non-blocking?

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.


2 Answers

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);
    };
}
like image 65
Michael McFadyen Avatar answered Oct 08 '22 04:10

Michael McFadyen


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);
            });
}
like image 21
Juan Avatar answered Oct 08 '22 04:10

Juan