Подтвердить что ты не робот

Java.net.HttpRetryException: не удается выполнить повторную попытку из-за аутентификации сервера, в потоковом режиме

У нас есть две части в нашем приложении:
Сервер - предоставлять услуги REST
Клиент - потреблять их через Spring restTemplate

В дополнение к статусу HTTP наш сервер возвращает тело HTTP с JSON, которое подробно описывает ошибку. Итак, я добавил собственный обработчик ошибок в restTemplate для обработки некоторых закодированных ошибок как ошибок - это помогает очень хорошо анализировать тело HTTP.

Но я получаю исключение путем анализа тела HTTP в случае HTTP/1.1 401 Unauthorized. Все остальные коды ошибок обрабатываются нормально (400, 402 и т.д.) Мы используем простую серверную логику, которая отправляет HTTP-ответ в случае ошибки, никаких специальных правил для различных типов ошибок:

writeErrorToResponse(int status, String errMsg, HttpServletResponse resp) throws IOException {
        response.setStatus(status);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String message = String.format("{\"error\":\"%s\"}", StringUtils.escapeJson(errMsg));
        resp.getWriter().println(message);
    }

Но на клиенте только HTTP/1.1 401 выдает исключение - "java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode"

Я сделал некоторые отладки и вижу, что причиной проблемы является код в SimpleClientHttpResponse:

HttpURLConnection.getInputStream()

Трассировка с Fiddler имеет следующие ответы: Сообщение правильно проанализировано на клиенте:

HTTP/1.1 402 Payment Required
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Connection: Close
Date: Sat, 25 May 2013 10:10:44 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

И сообщение, которое является причиной исключения:

HTTP/1.1 401 Unauthorized
X-Powered-By: Servlet/3.0
Content-Type: application/json
Content-Language: en-GB
Content-Length: 55
Date: Sat, 25 May 2013 11:00:21 GMT
Server: WebSphere Application Server/8.0

{"error":"I cant find that user.  Please try again."}

Что может быть причиной java.net.HttpRetryException в этой ситуации?

Кроме того: несколько раз назад этот механизм работал нормально. Но так как мы изменили много кода в приложении.

4b9b3361

Ответ 1

Я столкнулся с той же проблемой при использовании SimpleClientHttpRequestFactory. Решив его, установив

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;

Проблема связана с блокировкой и последующим механизмом повторной аутентификации.

Вы также можете отключить куски с помощью HttpClientPolicy

Ответ 2

Я думаю, что передача настроенного HttpComponentsClientHttpRequestFactory в ваш RestTemplate поможет. Здесь вы можете найти решение о том, как это сделать.

Причина, по которой я использовал такое решение для разработки, заключалась в том, чтобы обрабатывать ответные сообщения в теле ответов об ошибках Http, таких как 401, 404 и т.д., а также позволить развертыванию приложения в среде на стороне реального сервера.

Ответ 3

Эта проблема сообщается в Spring Framework.

Ссылка: https://jira.spring.io/browse/SPR-9367

Копирование из справочника: очень сложно (невозможно) обработать ответ 401 в RestTemplate с настройками по умолчанию. На самом деле это возможно, но вы должны предоставить обработчик ошибок и фабрику запросов. Обработчик ошибок был очевиден, но проблема в том, что фабрика запросов по умолчанию использует java.net, который может выдавать HttpRetryException, когда вы пытаетесь просмотреть код состояния ответа (несмотря на то, что он, очевидно, доступен). Решением является использование HttpComponentsClientHttpRequestFactory. Например

template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
template.setErrorHandler(new DefaultResponseErrorHandler() {
    public boolean hasError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = response.getStatusCode();
        return statusCode.series() == HttpStatus.Series.SERVER_ERROR;
    }
});

HttpComponentsClientHttpRequestFactory требует ниже зависимости. Добавьте ниже зависимости в вашем файле POM:

<dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
</dependency>