【问题标题】:HttpClient stuck without any exceptionHttpClient 卡住了,没有任何异常
【发布时间】:2012-03-29 12:16:44
【问题描述】:

我正在开发一个长时间运行的应用程序,它大量使用来自 apache 的 HttpClient。

在我的第一次测试运行中,该应用程序运行良好,直到它卡住了。它没有停止,也没有抛出任何异常,它只是坐在那里无所事事。

我刚刚进行了第二次跑步,并停止了时间,大约在 1 分钟后停止了。 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());
}

应用程序在它需要的 URL 上反复调用 httputil.getContentAsString()

【问题讨论】:

  • 也许你的实体是一个空字符串。
  • 那么我的方法仍然会返回那个空字符串,不是吗?或者至少抛出一个异常?
  • 我也有同样的问题。 httpEntity.consumeContent() 救救我。 stackoverflow.com/questions/9505358/…
  • 你解决过这个问题吗?
  • @Arya 这是一个超时问题。当我向连接添加超时时,它被解决了 IIRC(很久以前......)。连接的根本问题是什么,我不记得了。

标签: java apache-commons-httpclient


【解决方案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 的两个答案都已被弃用。我不确定是否有另一种方法,但我的方法是使用构建器范例 HTTPClientBuilder。

    例如

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

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

    增加最大连接数:

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

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

    【讨论】:

      【解决方案3】:

      我在另一个帖子中给出了类似的答案(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);
      

      【讨论】:

      • 谢谢你,你的解决方案有效,我一直被错误地认为我是速率受限的。
      【解决方案4】:

      您还没有说您使用的是哪个版本的 HttpClient,但假设它是版本 4,this blog article 解释了该怎么做。

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

      【讨论】:

      • 我相信这已经被弃用了
      【解决方案5】:

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

      【讨论】:

      • 我至今仍面临这个问题。我认为我的错误报告已关闭,因为我无法解释事物属性并重现它。但我认为重现此错误的最佳方法是在发布请求中间断开连接。我相信即使设置了超时也会让它卡住
      【解决方案6】:

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

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

      这是对的:

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

      希望对某人有所帮助。

      【讨论】:

        【解决方案7】:

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

        这里将parameters 设置为HttpParams 作为DefaultHttpClient 的构造函数的一部分,包括

        http.socket.timeout:定义socket超时时间(SO_TIMEOUT) 毫秒,这是等待数据的超时时间,或者,把 不同的是,两个连续数据之间的最大周期不活动 包)。超时值为零被解释为无限 超时。此参数需要 java.lang.Integer 类型的值。如果 不设置此参数,读操作不会超时(无限 超时)。

        这会在连接上设置一个超时,所以在设置的超时之后会抛出一个异常。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-22
          • 1970-01-01
          • 2015-03-29
          相关资源
          最近更新 更多