【问题标题】:Using Apache HttpClient how to set the TIMEOUT on a request and response使用 Apache HttpClient 如何在请求和响应中设置 TIMEOUT
【发布时间】:2012-03-26 14:15:43
【问题描述】:

我需要为我们向服务(不是 Web 服务)发出的 Http 请求设置超时时间。我们正在使用 Apache HTTP 客户端。我添加了这两行代码来设置请​​求和响应服务的超时时间。

HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);

1) 目前我已将 10 秒设置为超时,因为我几乎立即看到来自服务的响应。我应该增加还是减少时间?

2) 当响应时间超过 10 秒时会发生什么?它会抛出异常吗?它会是什么异常?在下面的代码中我还需要添加什么来设置超时。

public HashMap<String, Object> getJSONData(String url) throw Exception{
    DefaultHttpClient httpClient = new DefaultHttpClient();
    HttpParams params = httpClient.getParams();
    HttpConnectionParams.setConnectionTimeout(params, 10000);
    HttpConnectionParams.setSoTimeout(params, 10000);
    HttpHost proxy = new HttpHost(getProxy(), getProxyPort());
    ConnRouteParams.setDefaultProxy(params, proxy);
    URI uri;
    InputStream data = null;
    try {
        uri = new URI(url);
        HttpGet method = new HttpGet(uri);
        HttpResponse response = httpClient.execute(method);
        data = response.getEntity().getContent();
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    Reader r = new InputStreamReader(data);
    HashMap<String, Object> jsonObj = (HashMap<String, Object>) GenericJSONUtil.fromJson(r);
    return jsonObj;
}

【问题讨论】:

    标签: java apache-commons-httpclient


    【解决方案1】:

    我猜很多人来这里是因为标题和HttpConnectionParams API 已被弃用。

    使用最新版本的 Apache HTTP 客户端,您可以使用请求参数设置这些超时:

    HttpPost request = new HttpPost(url);
    
    RequestConfig requestConfig = RequestConfig.custom()
      .setSocketTimeout(TIMEOUT_MILLIS)
      .setConnectTimeout(TIMEOUT_MILLIS)
      .setConnectionRequestTimeout(TIMEOUT_MILLIS)
      .build();
    
    request.setConfig(requestConfig);
    

    或者,您也可以在创建 HTTP 客户端时使用 HTTP 客户端的构建器 API 进行设置,但您还需要使用自定义套接字配置构建自定义连接管理器。

    configuration example file 是了解如何配置 Apache HTTP 客户端的绝佳资源。

    【讨论】:

      【解决方案2】:

      您会看到ConnectTimeoutExceptionSocketTimeoutException 的例外情况。您使用的实际超时值应该是您的应用程序愿意等待的最长时间。关于读取超时的一个重要注意事项是它对应于套接字读取的超时。所以这不是允许完整响应到达的时间,而是给予单个套接字读取的时间。因此,如果有 4 次套接字读取,每次需要 9 秒,那么您的总读取时间为 9 * 4 = 36 秒。

      如果您想指定响应到达的总时间(包括连接和总读取时间),您可以将调用包装在一个线程中并为此使用线程超时。例如,我通常会这样做:

      Future<T> future = null;
      future = pool.submit(new Callable<T>() {
          public T call() {
              return executeImpl(url);
          }   
      }); 
      
      try {
          return future.get(10, TimeUnit.SECONDS);
      }   
      catch (InterruptedException e) {
          log.warn("task interrupted", name);
      }   
      catch (ExecutionException e) {
          log.error(name + " execution exception", e); 
      }   
      catch (TimeoutException e) {
          log.debug("future timed out", name);
      }
      

      上面代码中的一些假设是:1) 这是在一个带有 url 参数的函数中,2) 它在一个带有 name 变量的类中,3) log 是一个 log4j 实例,4) pool 是一个 some线程池执行器。请注意,即使使用线程超时,也应该在 HttpClient 上指定连接和套接字超时,这样慢请求就不会占用线程池中的资源。另请注意,我使用线程池,因为通常我在 Web 服务中使用它,因此线程池在一堆 tomcat 线程之间共享。您的环境可能不同,您可能更愿意为每次调用简单地生成一个新线程。

      此外,我通常会看到通过参数的成员函数设置的超时,如下所示:

      params.setConnectionTimeout(10000);
      params.setSoTimeout(10000);
      

      但也许你的语法也适用(不确定)。

      【讨论】:

      • 如果我必须允许完整响应时间到达,我需要设置/添加什么
      • 你能解释一下你所说的 4 socket read 是什么意思吗?如果它们是 4 个套接字读取,那么将有 4 个不同的请求与该读取相关联。
      • 不,响应可以分块出现。如果您查看任何低级套接字代码,您将看到read() 发生在一个while 循环中,read() 的返回值是读取的字节数。不要求整个响应来自单个套接字读取。我会更新我的答案以包含更多细节。
      • 设置超时的语法有效。我已经对其进行了测试并且工作正常。
      • 你不是说:return future.get(10, TimeUnit.SECONDS)?还是真的要等一万秒?
      猜你喜欢
      • 2015-03-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2017-07-04
      • 1970-01-01
      • 1970-01-01
      • 2014-11-09
      相关资源
      最近更新 更多