總覽
本教程主要讨論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.Timer
和
java.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