Spring WebClient Filters

1. Overview

In this tutorial, we’re going to explore WebClient filters in Spring WebFlux, a functional, reactive web framework.

2. Request Filters

A filter can intercept, examine, and modify a client request (or response). Filters are very suitable for adding functionality to every single request since the logic stays in one place. Use cases include monitoring, modifying, logging, and authenticating client requests, just to mention a few.

A request has an ordered chain of zero or more filters.

In Spring Reactive, filters are instances of the functional interface ExchangeFilterFunction. The filter function has two parameters: the ClientRequest to modify and the next ExchangeFilterFunction.

Usually, a filter function returns by calling the next one in the filter chain:

ExchangeFilterFunction filterFunction = (clientRequest, nextFilter) -> {
    LOG.info("WebClient fitler executed");
    return nextFilter.exchange(clientRequest);
};

3. WebClient Filtering

After implementing a request filter, we have to “attach” it to the WebClient instance. This can be only done while creating the WebClient.

So then, let’s see how to create a WebClient. The first option is to invoke WebClient.create() with or without a base URL:

WebClient webClient = WebClient.create();

This, unfortunately, doesn’t allow to add a filter. The second option, then, is the one we’re looking for.

By using the WebClient.builder() we’re able to add filters:

WebClient webClient = WebClient.builder()
  .filter(filterFunction)
  .build();

4. A Custom Filter

Let’s start with a filter that counts the HTTP GET requests sent by the client.

The filter examines the request method and increases a “global” counter in case of a GET request:

ExchangeFilterFunction countingFunction = (clientRequest, nextFilter) -> {
    HttpMethod httpMethod = clientRequest.method();
    if (httpMethod == HttpMethod.GET) {
        getCounter.incrementAndGet();
    }
    return nextFilter.exchange(clientRequest);
};

The second filter we’ll define appends a version number to the request URL path. We utilize the ClientRequest.from() method to create a new request object from the current one and set the modified URL.

Subsequently, we continue executing the filter chain with the new modified request object:

ExchangeFilterFunction urlModifyingFilter = (clientRequest, nextFilter) -> {
    String oldUrl = clientRequest.url().toString();
    URI newUrl = URI.create(oldUrl + "/" + version);
    ClientRequest filteredRequest = ClientRequest.from(clientRequest)
      .url(newUrl)
      .build();
    return nextFilter.exchange(filteredRequest);
};

Next, let’s define a filter to log the methods of sent requests along with their URLs. These details are available in the request object.

All we have to do then is to print to some output stream:

ExchangeFilterFunction loggingFilter = (clientRequest, nextFilter) -> {
    printStream.print("Sending request " + clientRequest.method() + " " + clientRequest.url());
    return nextFilter.exchange(clientRequest);
};

5. A Standard Filter

Finally, let’s look into basic authentication – a very common use case of request filtering.

The helper class ExchangeFilterFunctions offers the basicAuthentication() filter function which takes care of adding the authorization header to the request.

As a result, we don’t need to define a filter for it:

WebClient webClient = WebClient.builder()
  .filter(ExchangeFilterFunctions.basicAuthentication(user, password))
  .build();

6. Conclusion

In this short article, we have explored filtering WebFlux clients in Spring.

As always, the code example can be found in over on GitHub.

Related posts:

REST Web service: Basic Authentication trong Jersey 2.x
Spring Boot - Enabling HTTPS
Java Program to Apply Above-Below-on Test to Find the Position of a Point with respect to a Line
JUnit5 Programmatic Extension Registration with @RegisterExtension
Lớp Properties trong java
Retrieve User Information in Spring Security
Java Program to Implement Dijkstra’s Algorithm using Queue
Java Program to Find the Longest Subsequence Common to All Sequences in a Set of Sequences
Java Program to Implement Branch and Bound Method to Perform a Combinatorial Search
Guide to the Synchronized Keyword in Java
Introduction to Spring Cloud OpenFeign
A Quick Guide to Spring MVC Matrix Variables
Lớp Arrarys trong Java (Arrays Utility Class)
Tính kế thừa (Inheritance) trong java
Java Program to Implement Aho-Corasick Algorithm for String Matching
Recommended Package Structure of a Spring Boot Project
Using Java Assertions
Phương thức forEach() trong java 8
Derived Query Methods in Spring Data JPA Repositories
Java Program to Implement Skew Heap
Java CyclicBarrier vs CountDownLatch
Jackson vs Gson
Spring WebClient Requests with Parameters
Java Program to Describe the Representation of Graph using Adjacency List
Giới thiệu Google Guice – Binding
“Stream has already been operated upon or closed” Exception in Java
DynamoDB in a Spring Boot Application Using Spring Data
Spring Boot - Bootstrapping
Java – Write to File
Wrapper Classes in Java
Java – Convert File to InputStream
Introduction to Apache Commons Text