天天看點

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.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