Spring WebClient - Как обрабатывать сценарии ошибок - PullRequest
1 голос
/ 19 февраля 2020

Мы используем org.springframework.web.reactive.function.client.WebClient с reactor.netty.http.client.HttpClient как часть Spring 5.1.9 для выполнения запросов с использованием метода exchange(). Документация для этого метода подчеркивает следующее:

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

Наше использование exchange() довольно основательно c, но документация для сценария ошибок ios мне неясна, и я хочу быть уверен что мы правильно высвобождаем ресурсы для всех результатов. По сути, у нас есть блокирующая реализация, которая делает запрос и возвращает ResponseEntity независимо от кода ответа:

    try {
        ...
        ClientResponse resp = client.method(method).uri(uri).syncBody(body).exchange().block();
        ResponseEntity<String> entity =  resp.toEntity(String.class).block();
        return entity;
    } catch (Exception e) {
        // log error details, return internal server error
    }

Если я понимаю реализацию, exchange() всегда даст нам ответ, если запрос был успешно отправлен независимо от кода ответа (например, 4xx, 5xx). В этом случае нам просто нужно вызвать toEntity(), чтобы получить ответ. Меня беспокоит сценарий ошибок ios (например, нет ответа, ошибки соединения низкого уровня и т. Д. c). Будет ли описанная выше обработка исключений охватывать все другие сценарии ios и будет ли у любого из них ответ, который необходимо использовать?

Примечание: ClientResponse.releaseBody() был введен только в 5.2

1 Ответ

1 голос
/ 15 марта 2020

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

В документации сказано:

ПРИМЕЧАНИЕ. При использовании ClientResponse с помощью метода exchange () WebClient необходимо убедиться, что тело используется или освобождено с помощью одного из следующие методы:

  1. body (BodyExtractor)
  2. bodyToMono (Class) или bodyToMono (ParameterizedTypeReference)
  3. bodyToFlux (Class) или bodyToFlux (ParameterizedTypeReference)
  4. toEntity (Class) или toEntity (ParameterizedTypeReference)
  5. toEntityList (Class) или toEntityList (ParameterizedTypeReference)
  6. toBodilessEntity ()
  7. releaseBody )

Вы также можете использовать bodyToMono (Void.class), если не ожидается никакого ответа. Однако имейте в виду, что соединение будет закрыто, а не помещено обратно в пул, если какой-либо контент поступит. Это в отличие от releaseBody (), который потребляет все тело и освобождает любое полученное содержимое.

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/reactive/function/client/ClientResponse.html

Вы можете попробовать использовать. вместо этого извлекайте () .exchange () и обрабатывайте ошибки в качестве предпочтения.

  public Mono<String> someMethod() {

    return webClient.method(method)
      .uri(uri)
      .retrieve()
      .onStatus(
        (HttpStatus::isError), // or the code that you want
        (it -> handleError(it.statusCode().getReasonPhrase())) //handling error request
      )
      .bodyToMono(String.class);


  }

  private Mono<? extends Throwable> handleError(String message) {
    log.error(message);
    return Mono.error(Exception::new);
  }

В этом примере я использовал исключение, но вы можете создать более конкретное исключение, задав c, а затем использовать некоторый обработчик исключений для возврата http статус, который вы хотите. Не рекомендуется использовать блок, лучше передать поток вперед.

...