Apache HttpClient 超时
1. 概述
本教程将展示如何使用 Apache HttpClient 4 配置超时。
2. HttpClient 4.3之前配置超时
2.1. 原始String参数
在 4.3 版本出来之前,HttpClient带有很多配置参数,所有这些都可以通过通用的、类似Map的方式进行设置。
有3 个超时参数需要配置:
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));
2.2. API
这些参数中更重要的——即前两个——也可以通过更安全的 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中没有自定义设置器,仍然需要通过setParameter方法手动设置。
3. 使用新的 4.3 配置超时.建造者
4.3 中引入的流畅的构建器 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();
这是以类型安全和可读的方式配置所有三个超时的推荐方法。
4. 超时属性解释
现在,让我们解释一下这些不同类型的超时意味着什么:
- Connection Timeout ( http.connection.timeout ) – 与远程主机建立连接的时间
- Socket Timeout ( http.socket.timeout ) – 建立连接后等待数据的时间;两个数据包之间不活动的最长时间
- Connection Manager Timeout ( http.connection-manager.timeout ) – 等待来自连接管理器/池的连接的时间
前两个参数——连接和套接字超时——是最重要的。但是,在高负载情况下,设置获取连接的超时时间肯定很重要,这就是为什么不应该忽略第三个参数的原因。
5. 使用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 秒。
请注意,连接超时将导致org.apache.http.conn.ConnectTimeoutException被抛出,而套接字超时将导致java.net.SocketTimeoutException。
6. 硬超时
虽然在建立 HTTP 连接和不接收数据时设置超时非常有用,但有时我们需要为整个请求设置硬超时。
例如,下载一个可能很大的文件就属于这一类。在这种情况下,连接可能会成功建立,数据可能会一直通过,但我们仍然需要确保操作不会超过某个特定的时间阈值。
HttpClient没有任何配置允许我们为请求设置整体超时;但是,它确实为请求提供了中止功能,因此我们可以利用该机制来实现一个简单的超时机制:
HttpGet getMethod = new HttpGet(
"http://localhost:8080/httpclient-simple/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.Timer和java.util.TimerTask来设置一个简单的延迟任务,该任务在 5 秒硬超时后中止 HTTP GET 请求。
7. 超时和 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
//...