«1. Обзор

В этом руководстве мы собираемся изучить фильтры WebClient в Spring WebFlux, функциональной реактивной веб-инфраструктуре.

2. Фильтры запросов

Фильтр может перехватывать, проверять и изменять клиентский запрос (или ответ). Фильтры очень подходят для добавления функциональности к каждому отдельному запросу, поскольку логика остается в одном месте. Варианты использования включают мониторинг, изменение, регистрацию и аутентификацию клиентских запросов, и это лишь некоторые из них.

Запрос имеет упорядоченную цепочку из нуля или более фильтров.

В Spring Reactive фильтры являются экземплярами функционального интерфейса ExchangeFilterFunction. Функция фильтра имеет два параметра: ClientRequest для изменения и следующий ExchangeFilterFunction.

Обычно функция фильтра возвращается, вызывая следующую в цепочке фильтров:

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

3. Фильтрация WebClient

После реализации фильтра запроса мы должны «прикрепить» его к экземпляру WebClient . Это можно сделать только при создании WebClient.

Итак, давайте посмотрим, как создать WebClient. Первый вариант — вызвать WebClient.create() с базовым URL или без него:

WebClient webClient = WebClient.create();

Это, к сожалению, не позволяет добавить фильтр. Второй вариант, значит, тот, который мы ищем.

Используя WebClient.builder(), мы можем добавлять фильтры:

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

4. Пользовательский фильтр

Начнем с фильтра, который подсчитывает запросы HTTP GET, отправленные клиентом.

Фильтр проверяет метод запроса и увеличивает «глобальный» счетчик в случае запроса GET:

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

Второй фильтр, который мы определим, добавляет номер версии к URL-пути запроса. Мы используем метод ClientRequest.from() для создания нового объекта запроса из текущего и установки измененного URL-адреса.

Затем мы продолжаем выполнять цепочку фильтров с новым измененным объектом запроса:

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);
};

Далее давайте определим фильтр для регистрации методов отправленных запросов вместе с их URL-адресами. Эти детали доступны в объекте запроса.

Все, что нам нужно сделать, это напечатать в некоторый выходной поток:

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

5. Стандартный фильтр

Наконец, давайте рассмотрим базовую аутентификацию — очень распространенный случай фильтрации запросов.

Вспомогательный класс ExchangeFilterFunctions предлагает функцию фильтра basicAuthentication(), которая добавляет заголовок авторизации к запросу.

В результате нам не нужно определять для него фильтр:

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

6. Заключение

В этой короткой статье мы рассмотрели фильтрацию клиентов WebFlux в Spring.

Как всегда, пример кода можно найти на GitHub.