ResponseEntityExceptionHandler возвращает пустое тело ответа для исключения 401

Я пытаюсь реализовать вызов Rest на сервер аутентификации с помощью RestTemplate и зарегистрировать ответ на случай, если сервер вернет исключение. Для этого я использовал ResponseEntityExceptionHandler для обработки исключений HttpClientErrorException и HttpServerErrorException.

public Response sendRequest(Request requestBody, String url, HttpMethod httpMethod, Response responseBody) {
    RestTemplate restTemplate = new RestTemplate();
    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestBody.getBody(),
            this.securityHeaders);
    ResponseEntity<? extends Response> response = restTemplate.exchange(url, httpMethod, request,
            responseBody.getClass());
    return response.getBody();
}

В настоящее время мой ResponseEntityExceptionHandler выглядит следующим образом

@ControllerAdvice
public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler {

private static Logger log = LoggerFactory.getLogger(RestResponseExceptionHandler.class);
private HttpHeaders headers = new HttpHeaders();

@ExceptionHandler(value = { HttpClientErrorException.class, HttpServerErrorException.class })
protected ResponseEntity<Object> handleConflict(HttpStatusCodeException ex, WebRequest request) {
    ErrorMessage responseBody = new ErrorMessage();
    try {
        JSONObject bodyOfException = new JSONObject(ex.getResponseBodyAsString());
        log.warn("{}| {}", ex.getStatusCode(), bodyOfException);
        responseBody.setErrorAndDescription(bodyOfException.optString("error"),
                bodyOfException.optString("error_description"));
    } catch (JSONException e) {
        log.error("{}| Bad authentication response body | Response Body | {}", ex.getStatusCode(),
                ex.getResponseBodyAsString());
    }

    return handleExceptionInternal(ex, responseBody, headers, ex.getStatusCode(), request);
}

}

Однако только для исключений HttpStatus 401 я получаю пустой текст ответа.

Пример журналов:

400| {"error_description":"Bad client credentials","error":"invalid_client"}

401| Bad authentication response body | Response Body | 

Кто-нибудь знает, как я могу получить тело ответа для исключений 401?

Редактировать: При использовании почтальона для вызова сервера аутентификации я получаю ненулевой 401 responseBody:

{
 "error": "invalid_token",
 "error_description": "Token was not recognised"
}

ваш журнал имеет два разных кода состояния 400 и 401

Deadpool 28.02.2019 22:38

Да, это журналы для 2 разных запросов, один с ответом 401, а другой с ответом 400.

TheStiff 01.03.2019 18:18
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
2
2 665
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как вы думаете, почему у HttpStatusCodeExceptionдолжен есть тело ответа? Это не так. Посмотрите на конструктор RestClientResponseException, его прямого суперкласса.

 ...

 * @param responseBody the response body content (may be {@code null})
 * @param responseCharset the response body charset (may be {@code null})
 */
public RestClientResponseException(
        String message, 
        int statusCode,
        String statusText,
        @Nullable HttpHeaders responseHeaders, 
        @Nullable byte[] responseBody, 
        @Nullable Charset responseCharset) { ... }

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

Да, я знаю, что responseBody может быть Null. Однако, когда я использую Postman для вызова сервера аутентификации, и я получаю ненулевой ответBody

TheStiff 28.02.2019 19:40

@TheStiff, не могли бы вы опубликовать ответ, который вы получили на звонок почтальона?

LppEdd 28.02.2019 19:41

Да, я добавил это в исходный пост

TheStiff 28.02.2019 19:44

@TheStiff Найдите DefaultResponseErrorHandler#handleError. Поставьте там точку останова и посмотрите на строку "byte[] body = getResponseBody(response);"

LppEdd 28.02.2019 19:47

Спасибо, я сделал, как вы сказали, и заметил, что для ответов 401 метод getResponseBody выдавал исключение. Что привело меня к правильному пути вокруг этого. Я разместил решение в качестве ответа в этом сообщении.

TheStiff 01.03.2019 18:20
Ответ принят как подходящий

Наконец-то я смог зарегистрировать тело ответа для исключения 401. Я добавил зависимость

org.apache.httpcomponents:httpclient

и настроена фабрика запросов шаблонов отдыха

    restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

По-видимому, фабрика запросов по умолчанию SimpleClientHttpRequestFactory не может прочитать тело ответа для статуса 401 Http.

Спасибо за ответ, тоже мучаюсь с этой проблемой. Ваше здоровье!

rudald 26.05.2021 15:46

Просто дополнительная помощь. Рассматриваемый класс - docs.spring.io/spring-framework/docs/current/javadoc-api/org‌​/….

benzen 23.09.2021 20:29

У меня была аналогичная проблема с ответом 400, и приведенное выше решение с использованием HttpComponentsClientHttpRequestFactory() не сработало. Вместо этого я смог прочитать тело, используя restTemplate.setFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory));. Не уверен, что у кого-то есть такая же проблема, но, надеюсь, это поможет, если выбранное решение не работает для вас.

Другие вопросы по теме