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, которые ему нужны.
7 ответов
Этот код устарел (получите 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);
Начиная с версии 4.4, оба ответа пользователей user2393012 и Stephen C. устарели. Я не уверен, есть ли другой способ сделать это, но способ, которым я делаю это, используя парадигму строителя, HTTPClientBuilder.
Ex.
HttpClients.custom().setConnectionTimeToLive(1, TimeUnit.MINUTES).build()
Очень похожая (на самом деле это могла быть проблема OP) проблема, о которой упоминал OP, также возникает, но из-за того, что Apache устанавливает для одновременных подключений по умолчанию только два подключения на клиента. Решением этой проблемы было бы увеличить максимальное количество соединений или закрыть их, если вы можете.
Чтобы увеличить максимальное количество подключений:
HttpClients.custom().setMaxConnPerRoute(100000).build()
Чтобы закрыть соединения, вы можете использовать BasicHttpClientConnectionManager и вызвать метод close для
Я дал аналогичный ответ в другой теме ( 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);
Вы не сказали, какую версию HttpClient вы используете, но предполагая, что это версия 4, в этой статье блога объясняется, что делать.
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
У меня все настройки тайм-аутов просто отлично, но я обнаружил, что у нас есть URL, который выполняет http-чанкинг, но не дает результатов (отлично работает в chrome, но в http-клиенте он зависает всегда, даже с установленным тайм-аутом). К счастью, я владею сервером и просто возвращаю мусор, и он больше не зависает. Это кажется уникальной ошибкой в том, что http-клиент плохо обрабатывает какой-то пустой случай фрагментирования (хотя я мог бы быть в стороне).... Я просто знаю, что он висит каждый раз на том же URL с пустыми данными и этим URL это http chunking csv загрузить обратно в наш http-клиент.
У меня была та же проблема, она застряла, потому что я не закрыл DefaultHttpClient.
Так что это неправильно
try{
DefaultHttpClient httpclient = new DefaultHttpClient();
...
} catch (Exception e){
e.PrintStackTrace();
}
И это правильно
try (DefaultHttpClient httpclient = new DefaultHttpClient()){
...
} catch (Exception e){
e.PrintStackTrace();
}
Надеюсь, это поможет кому-то.
По умолчанию HttpClient не делает тайм-аут (что вызывает больше проблем, чем помогает). То, что вы описываете, может быть аппаратной проблемой, если ваш сетевой адаптер умер, HttpClient зависнет.
Вот параметры, установленные для HttpParams как часть конструктора DefaultHttpClient, включая
http.socket.timeout: определяет время ожидания сокета (SO_TIMEOUT) в миллисекундах, которое является временем ожидания для ожидания данных или, другими словами, максимальным периодом бездействия между двумя последовательными пакетами данных). Значение времени ожидания, равное нулю, интерпретируется как бесконечное время ожидания. Этот параметр ожидает значение типа java.lang.Integer. Если этот параметр не задан, для операций чтения не истечет время ожидания (бесконечное время ожидания).
Это установит тайм-аут для соединения, поэтому после установленного тайм-аута будет сгенерировано исключение.