Перейти к основному содержимому

Как получить тело ответа при тестировании кода состояния в WebFlux WebClient

· 3 мин. чтения

1. Обзор

Часто полезно использовать код состояния из ответа HTTP, чтобы определить, что приложение должно делать дальше с данным ответом.

В этом руководстве мы рассмотрим, как получить доступ к коду состояния и тексту ответа, возвращаемому из запроса REST, с помощью WebClient WebFlux.

WebClient был представлен в Spring 5 и может использоваться для асинхронного ввода-вывода при вызове служб RESTful.

2. Вариант использования

При выполнении вызовов RESTful к другим службам приложения обычно используют возвращенный код состояния для запуска различных функций. Типичные варианты использования включают изящную обработку ошибок, инициирование повторных попыток запроса и определение ошибки пользователя.

Таким образом, при совершении вызовов REST часто недостаточно просто получить код ответа. Иногда нам также нужно тело ответа.

В следующих примерах давайте посмотрим, как мы можем проанализировать тело ответа от клиента REST WebClient . Мы свяжем наше поведение с возвращенным кодом состояния и будем использовать два метода извлечения кода состояния, предоставляемые WebClient : onStatus и ExchangeFilterFunction.

3. Использование onStatus

onStatus — это встроенный механизм, который можно использовать для обработки ответа WebClient . Это позволяет нам применять детализированную функциональность на основе конкретных ответов (таких как 400, 500, 503 и т. д.) или категорий статусов (таких как 4XX, 5XX и т. д.):

WebClient
.builder()
.build()
.post()
.uri("/some-resource")
.retrieve()
.onStatus(
HttpStatus.INTERNAL_SERVER_ERROR::equals,
response -> response.bodyToMono(String.class).map(Exception::new))

Метод onStatus требует двух параметров. Первый — это предикат, который принимает код состояния. Выполнение второго параметра основано на выводе первого. Вторая — это функция, которая сопоставляет ответ с Mono или Exception.

В этом случае, если мы увидим INTERNAL_SERVER_ERROR (т. е. 500), мы возьмем тело с помощью bodyToMono, а затем сопоставим его с новым Exception .

Мы можем связать вызовы onStatus , чтобы обеспечить функциональность для различных состояний:

Mono<String> response = WebClient
.builder()
.build()
.post()
.uri("some-resource")
.retrieve()
.onStatus(
HttpStatus.INTERNAL_SERVER_ERROR::equals,
response -> response.bodyToMono(String.class).map(CustomServerErrorException::new))
.onStatus(
HttpStatus.BAD_REQUEST::equals,
response -> response.bodyToMono(String.class).map(CustomBadRequestException::new))
...
.bodyToMono(String.class);

// do something with response

Теперь вызовы onStatus сопоставляются с нашими пользовательскими исключениями. Мы определили типы исключений для каждого из двух статусов ошибок. Метод onStatus позволяет нам использовать любой выбранный нами тип.

4. Использование функции ExchangeFilterFunction

ExchangeFilterFunction — это еще один способ обработки определенных кодов состояния и получения тела ответа . В отличие от onStatus фильтр обмена является гибким и применяется к функциям фильтра на основе любого логического выражения.

Мы можем извлечь выгоду из гибкости функции ExchangeFilterFunction для охвата тех же категорий, что и функция onStatus .

Во-первых, мы определим метод для обработки возвращаемой логики на основе кода состояния, заданного ClientResponse :

private static Mono<ClientResponse> exchangeFilterResponseProcessor(ClientResponse response) {
HttpStatus status = response.statusCode();
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
return response.bodyToMono(String.class)
.flatMap(body -> Mono.error(new CustomServerErrorException(body)));
}
if (HttpStatus.BAD_REQUEST.equals(status)) {
return response.bodyToMono(String.class)
.flatMap(body -> Mono.error(new CustomBadRequestException(body)));
}
return Mono.just(response);
}

Далее мы определим фильтр и используем ссылку на метод для нашего обработчика:

ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction
.ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor);

Подобно вызовам onStatus , мы сопоставляем наши типы исключений при ошибке. Однако использование Mono.error завершит это исключение в ReactiveException. Эту вложенность следует учитывать при обработке ошибки .

Теперь давайте применим это к экземпляру WebClient , чтобы добиться того же эффекта, что и связанный вызов onStatus :

Mono<String> response = WebClient
.builder()
.filter(errorResponseFilter)
.build()
.post()
.uri("some-resource")
.retrieve()
.bodyToMono(String.class);

// do something with response

5. Вывод

В этой статье мы рассмотрели несколько методов получения тела ответа на основе заголовка состояния HTTP . Основываясь на коде состояния, метод onStatus позволяет нам подключать определенные функции. Кроме того, мы можем использовать метод фильтра , чтобы подключить метод общего назначения для обработки постобработки всех ответов.

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