我正在开发一个长期运行的应用程序,该应用程序大量使用来自apache的HttpClient。
在我的第一次测试运行中,应用程序运行良好,直到它被卡住。它没有停止,它没有抛出任何异常,只是坐在那里什么都不做。
我刚刚做了第二次跑步并停止了时间,并在大约停止后停止了。 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。
此代码现已弃用(获取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。
防爆。
HttpClients.custom().setConnectionTimeToLive(1, TimeUnit.MINUTES).build()
OP提到的问题也非常类似(实际上可能是OP问题),但是由于Apache将默认并发连接设置为每个客户端只有两个连接。对此的解决方案是增加最大连接数或关闭它们(如果可以)。
要增加最大连接数:
HttpClients.custom().setMaxConnPerRoute(100000).build()
要关闭连接,可以使用BasicHttpClientConnectionManager并调用close方法
你还没有说过你正在使用哪个版本的HttpClient,但假设它是版本4,this blog article解释了该怎么做。
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
我在另一个帖子中给出了类似的答案(HttpClient hangs on socketRead0 with successfully executed method)
在我的例子中,我在请求上设置了connectionTimeout和socketTimeout,但是在建立SSL连接期间没有使用连接套接字。因此,我有时会在SSL握手期间挂起。下面是一些使用v4.4设置所有3个超时的代码(也在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);
我所有的超时设置都很好,但我发现我们在url上做了http分块但没有发送结果(在chrome中工作正常,但在http客户端它甚至挂起,即使设置了超时)。幸运的是,我拥有服务器,只是返回一些垃圾,它不再挂起。这似乎是一个非常独特的错误,http客户端不能很好地处理某种空的分块情况(虽然我可能会离开)....我只知道它每次挂在同一个网址上,空数据和该网址是http chunking csv下载回我们的http客户端。
默认情况下,HttpClient不会超时(这会导致更多问题)。您所描述的可能是硬件问题,如果您的网络适配器死亡,HttpClient将挂起。
以下是parameters设置为HttpParams作为DefaultHttpClient构造函数的一部分,包括
http.socket.timeout:以毫秒为单位定义套接字超时(SO_TIMEOUT),这是等待数据的超时,换句话说,两个连续数据包之间的最大周期不活动。超时值为零被解释为无限超时。此参数需要java.lang.Integer类型的值。如果未设置此参数,则读取操作不会超时(无限超时)。
这将在连接上设置超时,因此在设置超时后将抛出异常。
我有同样的问题,因为我没有关闭DefaultHttpClient而卡住了。 所以这是错的:
try{
DefaultHttpClient httpclient = new DefaultHttpClient();
...
} catch (Exception e){
e.PrintStackTrace();
}
这是对的:
try (DefaultHttpClient httpclient = new DefaultHttpClient()){
...
} catch (Exception e){
e.PrintStackTrace();
}
希望它可以帮助某人。