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

HttpClient застрял без каких-либо исключений

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

В моем первом тестовом прогоне приложение отлично работало, пока оно не застряло. Это не было остановлено, это не вызвало каких-либо исключений, оно просто сидит там, ничего не делая.

Я сделал второй запуск только сейчас и остановил время, и он остановился после ок. 24 часа подряд. Кроме того, я заметил, что подключение к Интернету моего ноутбука, на котором я его запускал, было прекращено в тот момент, когда приложение застряло. Мне пришлось перезагрузить адаптер WLAN, чтобы сеть снова запущена.

Приложение, однако, не вернулось к работе после того, как соединение снова запустилось. И теперь он снова застрял.

Есть ли какой-либо контроллер тайм-аута, о котором я не знаю в HttpClient? Почему мое приложение не выдает исключение, когда соединение не работает?

Часть, использующая клиент, выглядит следующим образом:

public HttpUtil(ConfigUtil config) {
    this.config = config;

    client = new DefaultHttpClient();
    client.getParams().setParameter(HttpProtocolParams.USER_AGENT, this.config.getProperty("httputil.userAgent"));
}

public String getContentAsString(String url) throws ParseException, ClientProtocolException, IOException {
    return EntityUtils.toString(
            client.execute(
                    new HttpGet(url)).getEntity());
}

Приложение неоднократно вызывает httputil.getContentAsString() для URL-адресов, которые ему нужны.

4b9b3361

Ответ 1

Этот код устарел (получите HttpParams и т.д.). Лучший способ это:

RequestConfig defaultRequestConfig = RequestConfig.custom()
    .setCookieSpec(CookieSpecs.BEST_MATCH)
    .setExpectContinueEnabled(true)
    .setStaleConnectionCheckEnabled(true)
    .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
    .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
    .build();

HttpGet httpGet = new HttpGet(url);    
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
    .setSocketTimeout(5000)
    .setConnectTimeout(5000)
    .setConnectionRequestTimeout(5000)
    .build();
httpGet.setConfig(requestConfig);

Ответ 2

Начиная с версии 4.4, оба ответа пользователей user2393012 и Stephen C устарели. Я не уверен, есть ли другой способ сделать это, но так, как я это делаю, это использование парадигмы builder, HTTPClientBuilder.

Исх.

HttpClients.custom().setConnectionTimeToLive(1, TimeUnit.MINUTES).build()

Очень похожая проблема (на самом деле, возможно, проблема с OP), на что указывает OP, но из-за того, что Apache устанавливает одновременные соединения по умолчанию только с двумя соединениями на одного клиента. Решением этого было бы увеличить максимальные соединения или закрыть их, если сможете.

Чтобы увеличить максимальные соединения:

HttpClients.custom().setMaxConnPerRoute(100000).build()

Чтобы закрыть соединения, вы можете использовать BasicHttpClientConnectionManager и вызвать метод close для

Ответ 3

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

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);

Ответ 4

Я дал аналогичный ответ в другом потоке (HttpClient зависает на socketRead0 с успешно выполненным методом)

В моем случае я устанавливал connectionTimeout и socketTimeout в запросе, но не в сокет соединения, используемый при установлении SSL-соединения. В результате я иногда буду висеть во время установления связи SSL. Ниже приведен код, который устанавливает все 3 таймаута, используя v4.4 (также проверенный в версии 4.5).

// Configure the socket timeout for the connection, incl. ssl tunneling
connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(200);
connManager.setDefaultMaxPerRoute(100);

SocketConfig sc = SocketConfig.custom()
    .setSoTimeout(soTimeoutMs)
    .build();

connManager.setDefaultSocketConfig(sc);

HttpClient client = HttpClients.custom()
            .setConnectionManager(connManager)
            .setConnectionManagerShared(true)
            .build();

// configure the timeouts (socket and connection) for the request
RequestConfig.Builder config = = RequestConfig.copy(RequestConfig.DEFAULT);
config.setConnectionRequestTimeout(connectionTimeoutMs);
config.setSocketTimeout(socketTimeoutMs);

HttpRequestBase req = new HttpGet(uri);
req.setConfig(config.build());

client.execute(req);

Ответ 5

У меня есть все настройки тайм-аутов, но я обнаружил, что у нас есть URL-адрес, который делает http-chunking, но не отправляет никаких результатов (отлично работает в chrome, но в http-клиенте он вешает навсегда даже с установленным таймаутом). К счастью, я владею сервером и просто возвращаю мусор, и он больше не зависает. Это кажется очень уникальной ошибкой в ​​том, что http-клиент не обрабатывает какой-то пустой случай с помехами (хотя я мог бы быть далеко).... Я просто знаю, что он зависает каждый раз на том же URL-адресе с пустыми данными и этим URL-адресом это http chunking csv download back to our http client.

Ответ 6

По умолчанию HttpClient не отключается (что вызывает больше проблем, чем помогает). То, что вы описываете, может быть проблемой аппаратного обеспечения, если ваш сетевой адаптер умер, HttpClient будет висеть.

Здесь параметры установлены на HttpParams как часть конструктора DefaultHttpClient, включая

http.socket.timeout: определяет тайм-аут сокета (SO_TIMEOUT) в миллисекунды, что является тайм-аутом для ожидания данных или по-разному, неактивность максимального периода между двумя последовательными данными пакеты). Значение тайм-аута нуля интерпретируется как бесконечное тайм-аут. Этот параметр ожидает значение типа java.lang.Integer. Если этот параметр не установлен, операции чтения не будут таймаутом (бесконечный Тайм-аут).

Это установит тайм-аут соединения, поэтому после установленного таймаута будет выбрано исключение.

Ответ 7

У меня была такая же проблема, она застряла, потому что я не закрыл DefaultHttpClient.
Так что это неправильно:

try{
    DefaultHttpClient httpclient = new DefaultHttpClient();
    ...
} catch (Exception e){
    e.PrintStackTrace();
}

И это правильно:

try (DefaultHttpClient httpclient = new DefaultHttpClient()){
    ...
} catch (Exception e){
    e.PrintStackTrace();
}

Надеюсь, что это поможет кому-то.