28

我正在开发一个长期运行的应用程序,它大量使用来自 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。

4

7 回答 7

13

此代码现已弃用(获取 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);
于 2013-11-02T12:03:28.883 回答
8

从 4.4 版开始,用户 user2393012 和 Stephen C 的两个答案都已被弃用。我不确定是否有另一种方法,但我的方法是使用构建器范例 HTTPClientBuilder。

前任。

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

一个与 OP 提到的问题非常相似(实际上可能是 OP 的问题)的问题也发生了,但这是由于 Apache 将默认并发连接设置为每个客户端只有两个连接。解决方案是增加最大连接数或尽可能关闭它们。

要增加最大连接数:

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

要关闭连接,您可以使用 BasicHttpClientConnectionManager 并调用 close 方法

于 2015-06-25T05:04:33.667 回答
7

我在另一个线程中给出了类似的答案(HttpClient 挂在 socketRead0 上,方法成功执行

就我而言,我在请求上设置了 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);
于 2016-01-04T19:21:30.957 回答
6

您还没有说您使用的是哪个版本的 HttpClient,但假设它是版本 4,这篇博客文章解释了该怎么做。

DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, connectionTimeoutMillis);
HttpConnectionParams.setSoTimeout(httpParams, socketTimeoutMillis);
于 2012-03-29T12:25:14.827 回答
4

我的所有超时设置都很好,但我发现我们在 url 上进行了 http 分块但不发送任何结果(在 chrome 中工作正常,但在 http 客户端中,即使设置了超时,它也会永远挂起)。幸运的是我拥有服务器并且只是返回一些垃圾并且它不再挂起。这似乎是一个非常独特的错误,因为 http 客户端不能很好地处理某种空分块情况(尽管我可能会离开)....我只知道它每次都挂在具有空数据和该 url 的同一个 url是 http 分块 csv 下载回我们的 http 客户端。

于 2013-10-04T19:12:41.127 回答
4

我有同样的问题,它卡住了,因为我没有关闭 DefaultHttpClient。
所以这是错误的:

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

这是正确的:

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

希望它可以帮助某人。

于 2015-08-27T13:43:44.370 回答
3

默认情况下,HttpClient 不会超时(这导致的问题多于帮助)。您所描述的可能是硬件问题,如果您的网络适配器死了,HttpClient 将挂起。

以下是作为DefaultHttpClient的构造函数的一部分设置为HttpParams的参数,包括

http.socket.timeout:以毫秒为单位定义套接字超时(SO_TIMEOUT),这是等待数据的超时时间,或者换句话说,两个连续数据包之间的最大不活动时间)。超时值为零被解释为无限超时。此参数需要 java.lang.Integer 类型的值。如果未设置此参数,则读取操作不会超时(无限超时)。

这将在连接上设置超时,因此在设置超时后将引发异常。

于 2012-03-29T12:33:01.223 回答