簡述
今天開始介紹下Apache HttpClient 4的全面指南,從基礎(chǔ)到高級進(jìn)階,本文是基礎(chǔ)知識一。
狀態(tài)碼
從Http響應(yīng)中得出狀態(tài)碼
發(fā)送Http請求后 - 我們返回一個(gè)org.apache.http.HttpResponse實(shí)例,我們可以獲取到響應(yīng)的狀態(tài)行,并隱式地訪問狀態(tài)代碼:
response.getStatusLine().getStatusCode()
使用它,我們可以驗(yàn)證從服務(wù)器收到的代碼是否是正確的:
@Test
public void test()
throws ClientProtocolException, IOException {
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(new HttpGet(SAMPLE_URL));
int statusCode = response.getStatusLine().getStatusCode();
assertThat(statusCode, equalTo(HttpStatus.SC_OK));
}
這里面,使用org.apache.http.HttpStatus中庫中提供的預(yù)定義狀態(tài)代碼。
超時(shí)
HttpClient可以配置超時(shí)的時(shí)間,接下來,我們看下如何使用。
通過字符串參數(shù)配置超時(shí)
HttpClient的自帶了大量的配置參數(shù),而所有的這些都可以在一個(gè)通用的Map集合中來設(shè)置。
有3個(gè)超時(shí)參數(shù)配置:
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));
通過API配置超時(shí)
這些參數(shù)中更重要的 - 即前兩個(gè) - 也可以通過更安全的API進(jìn)行設(shè)置:
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
第三個(gè)參數(shù)在HttpConnectionParams中沒有自定義setter ,它仍然需要通過setParameter方法手動設(shè)置。
使用新的4.3配置超時(shí)
4.3中引入新API來設(shè)置超時(shí)的方法,這個(gè)更方便快捷:
int timeout = 5;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
這是以類型安全且可讀的方式配置所有三個(gè)超時(shí)的推薦方法。
超時(shí)屬性說明
現(xiàn)在,讓我們解釋一下這些不同類型的超時(shí)意味著什么:
- 連接超時(shí)(http.connection.timeout) - 建立與遠(yuǎn)程主機(jī)的連接的時(shí)間
- socket超時(shí)(http.socket.timeout) - 等待數(shù)據(jù)的時(shí)間-建立連接后; 兩個(gè)數(shù)據(jù)包之間的最長不活動時(shí)間
- 連接管理器超時(shí)(http.connection-manager.timeout) - 從連接管理器/池中獲取一個(gè)連接的等待時(shí)間。
前兩個(gè)參數(shù),connection和socket超時(shí)是最重要的。但是,在高負(fù)載情況下設(shè)置獲取連接的超時(shí)非常重要,這就是不應(yīng)忽略第三個(gè)參數(shù)的原因。
強(qiáng)制超時(shí)
雖然設(shè)置建立HTTP連接和不接收數(shù)據(jù)的超時(shí)非常有用,但有時(shí)我們需要為整個(gè)請求設(shè)置強(qiáng)制超時(shí)。
例如,可能大型文件的下載符合此類別。在這種情況下,可以成功建立連接,數(shù)據(jù)可以一直通過,但是我們?nèi)匀恍枰_保操作不會超過某個(gè)特定時(shí)間閾值。
HttpClient沒有任何允許我們?yōu)檎埱笤O(shè)置總超時(shí)的配置; 但是,它確實(shí)為請求提供了中止功能,因此我們可以利用該機(jī)制實(shí)現(xiàn)一個(gè)簡單的超時(shí)機(jī)制:
HttpGet getMethod =new HttpGet("http://localhost:8080/");
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來設(shè)置一個(gè)簡單的延遲任務(wù),該任務(wù)在5秒強(qiáng)制超時(shí)后中止HTTP GET請求。
DNS循環(huán)超時(shí)
一些較大的域名將使用DNS循環(huán)配置是很常見的,基本上具有映射到多個(gè)IP地址的相同域名。這引發(fā)了針對此類域的超時(shí)的新挑戰(zhàn),原因很簡單,因?yàn)镠ttpClient將嘗試連接到超時(shí)的域:
HttpClient獲取到該域的IP路由列表
它嘗試第一個(gè) - 超時(shí)
它嘗試第二個(gè) - 也超時(shí)
等等 …
因此,正如你所看到的 - 當(dāng)我們期望它時(shí),整體操作不會超時(shí)。相反 - 當(dāng)所有可能的路線超時(shí)時(shí)它會超時(shí)。更重要的是 - 這將完全透明地發(fā)生在客戶端上(除非你在DEBUG級別配置了日志)。
這是一個(gè)可以運(yùn)行并復(fù)制此問題的簡單示例:
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.domain.com");
response = client.execute(request);
你將注意到具有DEBUG日志級別的重試邏輯:
DEBUG o.a.h.i.c.HttpClientConnectionOperator - Connecting to www.domain.com/173.194.34.212:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
Connect to www.domain.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.domain.com/173.194.34.208:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
Connect to www.domain.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.domain.com/173.194.34.209:81
DEBUG o.a.h.i.c.HttpClientConnectionOperator -
Connect to www.domain.com/173.194.34.209:81 timed out. Connection will be retried using another IP address
//...
小結(jié)
本文介紹了狀態(tài)碼和超時(shí)的配置以及機(jī)制,希望對你有所幫助。