Вопрос по java, httpclient – Временная ошибка Apache HttpClient: NoHttpResponseException

58

У меня есть веб-сервис, который принимает метод POST с XML. Он работает нормально, а затем по случайному случаю не может связаться с сервером, выбрасывая IOException с сообщениемThe target server failed to respond, Последующие звонки работают нормально.

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

Я попробовал пару вещей ...

Я настраиваю обработчик повторов как

<code>HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {

            public boolean retryRequest(IOException e, int retryCount, HttpContext httpCtx) {
                if (retryCount >= 3){
                    Logger.warn(CALLER, "Maximum tries reached, exception would be thrown to outer block");
                    return false;
                }
                if (e instanceof org.apache.http.NoHttpResponseException){
                    Logger.warn(CALLER, "No response from server on "+retryCount+" call");
                    return true;
                }
                return false;
            }
        };

        httpPost.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryHandler);
</code>

но эта повторная попытка не была вызвана. (да, я использую правильное предложение instanceof). При отладке этот класс никогда не вызывается.

Я даже пытался настроитьHttpProtocolParams.setUseExpectContinue(httpClient.getParams(), false); но бесполезно. Может кто-нибудь подсказать, что я могу сделать сейчас?

IMPORTANT Помимо выяснения, почему я получаю исключение, одна из важных проблем, с которыми я сталкиваюсь, заключается в том, почему здесь не работает ретранслятор?

Я попытался Fiddler, чтобы бомбардировать сервер назначения, но он работал нормально. Я даже пытался выполнить те же шаги, чтобы воспроизвести ошибку, используя fiddler, но не повезло! Em Ae
Я не думаю, что это что-то с клиентским кодом. Может быть, сервер назначения слишком занят обработкой ответов? kosa
Кот. Нет, это фиктивный сервис, и он не получает ничего, кроме моих звонков. Em Ae
На каком веб-сервере запущена служба, и в течение 10-15 минут ожидания служба получает другие запросы или служба бездействует? Shawn

Ваш Ответ

5   ответов
2

HttpClient 4.4 страдает от ошибки в этой области, связанной с проверкой возможно устаревших соединений перед возвратом запрашивающей стороне. Этоdidn't проверить, было ли соединение устаревшим, и это затем приводит к немедленномуNoHttpResponseException.

Эта проблема была решена в HttpClient 4.4.1. Увидетьэто джира изаметки о выпуске

Я использую версию 4.5.3, но все еще получаюNoHttpResponseException, В моем случае я получаю это исключение в каждом четвертом или пятом непрерывном запросе, а не в первом. Любая идея, что может быть причиной в моем случае?
91

Скорее всего, постоянные соединения, которые поддерживаются диспетчером соединений, становятся устаревшими. Таким образом, целевой сервер завершает соединение на своем конце, при этом HttpClient не может реагировать на это событие, когда соединение находится в режиме ожидания, что делает соединение наполовину закрытым или «устаревшим». Обычно это не проблема. HttpClient использует несколько методов для проверки правильности соединения при аренде его из пула. Даже если проверка устаревшего соединения отключена и устаревшее соединение используется для передачи сообщения запроса, выполнение запроса обычно завершается неудачно в операции записи с SocketException и автоматически повторяется. Однако при некоторых обстоятельствах операция записи может завершиться без исключения, и последующая операция чтения возвращает -1 (конец потока). В этом случае у HttpClient нет другого выбора, кроме как предположить, что запрос выполнен успешно, но сервер не смог ответить наиболее вероятно из-за непредвиденной ошибки на стороне сервера.

Самый простой способ исправить ситуацию - это удалить устаревшие соединения и соединения, которые простаивали дольше, чем, скажем, 1 минута из пула после периода бездействия. Для подробностей смотритеэтот раздел учебника HttpClient.

Безопасно ли перехватывать это исключение NoHttpResponseException и выполнять повторную попытку?
Это зависит от многих факторов. Этоshould быть безопасным для безопасных и идемпотентных методов, если сервер соответствует спецификации HTTP в отношении безопасности и идемпотентности метода.
@oleg, в чем разница между неактивными и просроченными соединениями?
Я использую HTTTPClient 4.5.1, здесь для двух непрерывных повторных попыток сервер не ответил, но в третий раз успешно, так почему он не подключается с первой попытки, даже если я оставил время 1 минуту, как указано.
Некоторые соединения могут иметь время истечения, после которого их следует считать недействительными / повторно используемыми. Свободные соединения полностью действительны и могут использоваться повторно, но на мгновение не используются.
2

Та же проблема для меня на apache http клиенте 4.5.5 добавление заголовка по умолчанию

Подключение: закрыть

решить проблему

2

В настоящее время большинство HTTP-соединенийсчитается постоянным, если не указано иное, Однако, чтобы сохранить ресурсы сервера, соединение редко остается открытым навсегда, время ожидания соединения по умолчанию для многих серверов довольно короткое, например, 5 секунд для Apache httpd 2.2 и выше.

org.apache.http.NoHttpResponseException Скорее всего, ошибка возникает из-за одного постоянного соединения, которое было закрыто сервером.

Можно установить максимальное время, в течение которого неиспользуемые соединения будут открыты в пуле клиентов Apache Http, в миллисекундах.

С Spring Boot, один из способов добиться этого:

public class RestTemplateCustomizers {
    static public class MaxConnectionTimeCustomizer implements RestTemplateCustomizer {

        @Override
        public void customize(RestTemplate restTemplate) {
            HttpClient httpClient = HttpClientBuilder
                .create()
                .setConnectionTimeToLive(1000, TimeUnit.MILLISECONDS)
                .build();

            restTemplate.setRequestFactory(
                new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    }
}

// In your service that uses a RestTemplate
public MyRestService(RestTemplateBuilder builder ) {
    restTemplate = builder
         .customizers(new RestTemplateCustomizers.MaxConnectionTimeCustomizer())
         .build();
}
В моем случае я получаю это исключение в каждом четвертом или пятом непрерывном запросе, а не в первом. Любая идея, что может быть причиной в моем случае?
14

Принятый ответ правильный, но не имеет решения. Чтобы избежать этой ошибки, вы можете добавить setHttpRequestRetryHandler (или setRetryHandler для компонентов apache 4.4) для своего HTTP-клиента, как вэтот ответ.

Повторить запрос POST с помощью предоставленного мною метода практически безопасно - потому что он обрабатывает и повторяет только исключение NoHttpResponseException, что гораздо более возможно благодаря стороне клиента, а не стороне сервера.
Вы спрашиваете, если POST безопасно повторить? Как принцип дизайна, PUT является идемпотентом. Повторная попытка POST может иметь непредвиденные последствия. Опять же, не все PUT написаны идемпотентно.
Учитывая, что исходный вопрос определяет POST, является ли обработчик повторных попыток правильным подходом здесь?
@Jehy Это совсем не безопасно ... NoHttpResponseException означает, что клиент не получил ответ, а не то, что сервер не получил и / или обработал запрос

Похожие вопросы