HttpClient系列-基礎(chǔ)知識(一)

簡述

今天開始介紹下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.Timerjava.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ī)制,希望對你有所幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第二章 連接管理 HttpClient有一個(gè)對連接初始化和終止,還有在活動連接上I/O操作的完整控制。而連接操作的...
    狂奔的蝸牛_wxc閱讀 1,399評論 0 0
  • iPhone的標(biāo)準(zhǔn)推薦是CFNetwork 庫編程,其封裝好的開源庫是 cocoa AsyncSocket庫,用它...
    Ethan_Struggle閱讀 2,357評論 2 12
  • 1 Overview 常見的微服務(wù)架構(gòu): 做好超時(shí)時(shí)間的限定,用于判定超時(shí)后資源能夠及時(shí)被釋放,用于處理其它的請求...
    檸檬夕閱讀 1,590評論 0 5
  • 6.1 公鑰密鑰加密原理 6.1.1 基礎(chǔ)知識 密鑰:一般就是一個(gè)字符串或數(shù)字,在加密或者解密時(shí)傳遞給加密/解密算...
    AndroidMaster閱讀 4,107評論 1 8
  • 前言 超文本傳輸協(xié)議(HTTP)也許是當(dāng)今互聯(lián)網(wǎng)上使用的最重要的協(xié)議了。Web服務(wù),有網(wǎng)絡(luò)功能的設(shè)備和網(wǎng)絡(luò)計(jì)算的發(fā)...
    狂奔的蝸牛_wxc閱讀 5,650評論 0 12

友情鏈接更多精彩內(nèi)容