HttpClient Timeout设置

总览

本教程主要讨论Apache HttpClient 4框架的timeout设置。如果想学习HttpClient的其他方面,请参考HttpClient教程

使用String参数配置Timeouts

HttpClient有许多参数配置,这些参数都可以使用一种通用的、类似map风格的方式进行设置。

以下是三个超时参数配置:

DefaultHttpClient httpClient = new DefaultHttpClient();
 
int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
httpParams.setParameter(
  CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
httpParams.setParameter(
  CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);
// httpParams.setParameter(
//   ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));

尤其注意最后一个参数——连接管理器超时,在使用4.3.0 或者 4.3.1版本时应该被注释掉,具体请参考jira说明。

使用API配置Timeout

以下是通过类型安全的API来设置的方式:

DefaultHttpClient httpClient = new DefaultHttpClient();
 
int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(
  httpParams, timeout * 1000); // http.connection.timeout
HttpConnectionParams.setSoTimeout(
  httpParams, timeout * 1000); // http.socket.timeout

在HttpConnectionParams中没有提供设置第三个参数的setter方法,因此仍然需要我们手动通过调用setParameter方法来设置。

##使用 4.3 Builder API配置Timeout

4.3版本引入了基于fluent、builder操作的API,以下是设置方式:

int timeout = 5;
RequestConfig config = RequestConfig.custom()
  .setConnectTimeout(timeout * 1000)
  .setConnectionRequestTimeout(timeout * 1000)
  .setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = 
  HttpClientBuilder.create().setDefaultRequestConfig(config).build();

这是一种基于类型安全和可读性来配置三个超时参数的推荐方式。

##超时属性解释

现在,我们来看一下这些不同类型超时参数的具体含义:

the Connection Timeout (http.connection.timeout) – 与远程服务器建立连接的时间

the Socket Timeout (http.socket.timeout) – 建立连接之后,等待远程服务器返回数据的时间,也就是两个数据包(请求包和响应包)之间不活动的最大时间。

the Connection Manager Timeout (http.connection-manager.timeout) – 从连接管理器/池中获取一个连接的等待时间。

前两个连接和socket超时的参数,是最重要的,但是获取一个连接的超时设置在高负载情况下也同样重要,这也就是第三个参数不能被忽略的原因所在。

使用 HttpClient

设置完上面的参数之后,HttpClient还不能被用来执行HTTP请求:

HttpGet getMethod = new HttpGet("http://host:8080/path");
HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

根据前面的客户端设置,连接到主机的超时时间是5秒,如果建立连接但没有收到数据,超时还将额外增加5秒。

注意这2个异常:

  • 连接超时返回的异常:org.apache.http.conn.ConnectTimeoutException
  • socket超时返回的异常:java.net.SocketTimeoutExceptio

硬超时:Hard Timeout

虽然给HTTP连接建立和等待返回结果设置超时时间十分有用,但是有时我们也需要给整个请求设置一个硬超时时间。

例如,要下载一个可能很大的文件放到当前分类,在这种情况下,也许成功建立了连接,文件数据也许会不断传递给我们,但是我们也需要确保这个操作不会超过给定时间的阈值。

HttpClient没有任何配置,允许我们给一个请求设定一个总的超时时间。然而,可以通过HttpClient为请求提供终止功能,我们可以利用这个机制来实现一个简单的超时策略:

HttpGet getMethod = new HttpGet(
  "http://localhost:8080/spring-security-rest-template/api/bars/1");
 
int hardTimeout = 5; // seconds
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        if (getMethod != null) {
            getMethod.abort();
        }
    }
};
new Timer(true).schedule(task, hardTimeout * 1000);
 
HttpResponse response = httpClient.execute(getMethod);
System.out.println(
  "HTTP Status of response: " + response.getStatusLine().getStatusCode());

我们利用java.util.Timerjava.util.TimerTask 来创建一个简单的延迟任务,实现在5秒硬超时之后,终止HTTP GET请求。

超时和DNS轮循需要注意的

一些大的域名使用DNS轮循调度配置是很常见的,本质上是一个域名映射到多个IP地址上。给这样的域名设置超时是一个新的挑战,仅仅是因为HttpClient将尝试连接到那个超时的域名:

  • HttpClient 获取域名的IP列表
  • 第一次尝试连接超时(由于我们的超时配置)
  • 第二次尝试连接也超时
  • 等等 …

因此,正如你所看到的,我们期望操作是不超时的。取而代之的是,当所有可能的路由超时的时候,整个操作就会超时。这对客户端来说是透明的(除非你配置了DEBUG级别的日志)。下面是一个简单的例子,您可以运行和重现这个问题:

int timeout = 3;
RequestConfig config = RequestConfig.custom().
  setConnectTimeout(timeout * 1000).
  setConnectionRequestTimeout(timeout * 1000).
  setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client = HttpClientBuilder.create()
  .setDefaultRequestConfig(config).build();
 
HttpGet request = new HttpGet("http://www.google.com:81");
response = client.execute(request);

在DEBUG日志中你将注意到以下重试逻辑:

DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.212:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.212:81 timed out. Connection will be retried using another IP address
 
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.208:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.208:81 timed out. Connection will be retried using another IP address
 
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.google.com/173.194.34.209:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator - 
 Connect to www.google.com/173.194.34.209:81 timed out. Connection will be retried using another IP address
//...

结论

本教程讨论了如何给HttpClient配置各种不同的可用timeout参数,还举例说明了给一个不间断的HTTP连接建立一个简单的硬超时机制。

可以在GitHub上下载这些例子的代码实现,该项目是基于Maven实现的,因此导入和运行它很容易。

编译自:http://www.baeldung.com/httpclient-timeout

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HttpClient 可以通过设置重试策略来实现重试操作。在 HttpClient 中,有两种方式可以设置重试策略: 1. 使用 HttpRequestRetryHandler 接口实现自定义重试策略 你可以自定义一个实现了 HttpRequestRetryHandler 接口的类,并在 HttpClient设置该重试处理器。例如,以下代码展示了一个最大重试次数为 3 的重试处理器实现: ``` HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() { public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 3) { // Do not retry if over max retry count return false; } if (exception instanceof InterruptedIOException) { // Timeout return false; } if (exception instanceof UnknownHostException) { // Unknown host return false; } if (exception instanceof ConnectTimeoutException) { // Connection refused return true; } if (exception instanceof SSLException) { // SSL handshake exception return false; } HttpClientContext clientContext = HttpClientContext.adapt(context); HttpRequest request = clientContext.getRequest(); boolean idempotent = !(request instanceof HttpEntityEnclosingRequest); if (idempotent) { // Retry if the request is considered idempotent return true; } return false; } }; CloseableHttpClient httpClient = HttpClients.custom() .setRetryHandler(myRetryHandler) .build(); ``` 以上代码中,我们将重试次数设置为 3,如果超过次数则不再尝试。HttpRequestRetryHandler 接口中的 retryRequest 方法定义了什么情况下需要重试,可以根据需要进行自定义。 2. 使用 HttpClientBuilder 设置重试策略 在 HttpClient 中,HttpClientBuilder 提供了多个重试策略,可以通过 setRetryHandler 方法来设置。例如,以下代码展示了一个最大重试次数为 3 的重试策略: ``` CloseableHttpClient httpClient = HttpClients.custom() .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) .build(); ``` 以上代码中,我们使用了 DefaultHttpRequestRetryHandler 类来实现重试操作,设置了最大重试次数为 3,以及当遇到 IOException 时是否重试。DefaultHttpRequestRetryHandler 类还有其他构造方法可以根据需要进行选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值