HttpClient застрял без каких-либо исключений - PullRequest
24 голосов
/ 29 марта 2012

Я занимаюсь разработкой долго работающего приложения, в котором интенсивно используется 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это нужно.

Ответы [ 7 ]

12 голосов
/ 02 ноября 2013

Этот код устарел (получите 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);
7 голосов
/ 25 июня 2015

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

Пример.

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

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

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

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

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

6 голосов
/ 29 марта 2012

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

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
5 голосов
/ 04 января 2016

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

В моем случае я устанавливал connectionTimeout и socketTimeout по запросу, но не по сокету соединения, используемому при установлении соединения SSL. В результате я иногда зависал во время рукопожатия SSL. Ниже приведен код, который устанавливает все 3 тайм-аута с использованием v4.4 (также протестирован в v4.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);
4 голосов
/ 04 октября 2013

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

3 голосов
/ 27 августа 2015

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

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

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

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

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

3 голосов
/ 29 марта 2012

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

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

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

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

...