簡介
最近在做一些開放接口應用的時候發現原有的一些應用大量使用了HttpComponent裏面的功能。從HttpComponent本身的介紹來說,它是一個實現Http協議很多操作功能的組件,在一些爬蟲和網絡應用開發中都得到大量的應用。因爲牽涉到的開放服務接口使用的是http rest服務,感覺httpcomponent很適合其中的場景。這裏結合項目中使用的一些場景來對其中的功能做一個簡單的總結。
HttpClient基本操作
在使用httpclient之前我們需要首先下載httpclient的jar包,裏面就包含了httpclient.jar, httpcore.jar等幾個文件。我們先看一個簡單的示例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
publicclass HTTPGetSample {
publicstaticvoid main(String[] args) throws ClientProtocolException, IOException {
String url = "http://www.google.com.hk/search?q=httpClient";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
System.out.println("Response Code: " +
response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line = "";
while((line = rd.readLine()) != null) {
System.out.println(line);
}
}
}
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; public class HTTPGetSample { public static void main(String[] args) throws ClientProtocolException, IOException { String url = "http://www.google.com.hk/search?q=httpClient"; HttpClient client = new DefaultHttpClient(); HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request); System.out.println("Response Code: " + response.getStatusLine().getStatusCode()); BufferedReader rd = new BufferedReader( new InputStreamReader(response.getEntity().getContent())); String line = ""; while((line = rd.readLine()) != null) { System.out.println(line); } } }
在這個示例裏我們嘗試用httpclient發送一個http get請求。請求的地址是對應到一個google search的url.仔細看上面的代碼,其實還是很簡單,首先創建一個HttpClient的對象,然後針對我們的http get操作創建一個HttpGet對象,並將請求url作爲參數傳給該對象。具體執行get操作的步驟是通過httpclient.execute()方法。這個方法裏將HttpGet對象作爲參數傳入。返回一個HttpResponse的結果。
我們通過讀取HttpResponse的結果就可以得到請求返回的詳細信息。這個過程和我們通過瀏覽器瀏覽某個網頁的效果相同。程序執行的部分結果如下:
Response Code: 200
<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">...
Response Code: 200 <!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">...
由於篇幅限制,省略了部分結果。
從前面示例裏我們可以看到通過HttpClient發送Http請求的基本套路:
1. 創建HttpClient對象。
2. 構造Http 請求對象。
3. 執行HttpClient對象的execute方法,將Http請求對象作爲該方法的參數。
4. 讀取execute方法返回的HttpResponse結果並解析。
ok,既然整體過程是這樣的話,我們後續使用post, put, delete等操作的過程也就大同小異了。在詳細討論這些方法使用之前我們先簡單的討論一下http協議裏的這幾種方法。
Http協議常用方法
關於http協議的介紹網上材料很多。總的來說,http協議規範了通信雙方交互的方式,基本上它是採用一種請求-應答的方式。客戶端發送請求給服務器端,然後服務器端發送響應回來。我們常用的幾種http操作的方法可以分爲可修改的和不可修改的。怎麼理解這個可修改和不可修改的意思呢?
在http協議裏,我們有的請求方法只是獲取服務器端資源的信息,默認的假定是不修改服務器端的狀態,這種方法稱爲不可修改的方法。比如說HttpGet, HttpHead, HttpOptions,HttpTrace。所以說這種請求方法是可以重複執行並返回相同結果的。我們對同一個資源執行若干次get操作,每次得到的結果都相同。而對於可修改的請求來說,主要有HttpPut, HttpPost, HttpDelete等。他們在規範裏分別對應着對資源的update, create和delete等操作。所以在一些web應用裏,我們提交表單的時候選擇的是http post操作。
除了http協議裏規定的這麼幾種方法,它本身還支持交互的內容,比如通過請求頭中間設定"accept", "Content-Type"等信息,指定我們交互的內容格式。他們可以是靜態文件類型的,比如說txt, .gif,.jpg等,也可以是一些其他文本如json, xml。在一些rest web服務裏面,我們指定的支持json或者xml格式的數據交換就可以通過這裏來定義。
我們剛看到了通過設定請求頭來指定通信的交互內容格式,那麼是否也可以指定請求體呢?在這裏是有可能的,只是針對不同的請求方法。比如說對HttpGet之類的方法,他們本身只是獲取服務器的內容不需要向服務器提交額外的信息,所以對於這一類的請求方法來說帶個請求體意義並不大。而對於那些要提交大量內容給服務器的請求如上傳文件或者提交表單信息的httpput, httppost請求,他們就有必要設置一個請求體。
有了前面的這些鋪墊,我們後面可以更加深入的分析一下httpclient中間幾種方法的結構和用法。
Http操作方法結構
HttpClient相關的uml結構圖如下:
我們關注的各種http方法都被定義成一個個獨立的類,他們都繼承自HttpRequestBase。其中比較特殊一點的是HttpPut, HttpPost,他們繼承自HttpEntityEnclosingRequestBase。爲什麼這兩個類要稍微特殊一點呢?這就是我們前面提到的他們要設置請求體,在HttpEntityEnclosingRequestBase裏有HttpEntity的成員變量,他們作爲這兩個方法特定的特性定義在這裏:
private HttpEntity entity;
public HttpEntity getEntity() {
returnthis.entity;
}
publicvoid setEntity(final HttpEntity entity) {
this.entity = entity;
}
private HttpEntity entity; public HttpEntity getEntity() { return this.entity; } public void setEntity(final HttpEntity entity) { this.entity = entity; }
HttpEntity是一個接口,根據具體傳入的參數類型我們可以選擇StringEntity, InputStreamEntity等。由此,對於這兩種有差別的請求方法來說,他們只是需要多增加一個setEntity的方法。
另外對於通用的設置請求頭部分,前面的示例代碼裏我們是使用了一種硬編碼的方式。我們也可以採用request.addHeader(Header)的方法。在HttpClient裏,Header是一個接口,我們可以創建兩種實現該接口的對象來作爲參數傳給addHeader方法。分別是BasicHeader, BufferedHeader。
總結
HttpClient通常用來作爲一個模擬http請求的工具。我們最常見的get, put, post, delete等方法在其中都通過具體定義的類來實現。當我們要發送某個具體的請求是,只需要創建對應請求的對象並設定請求頭或者請求體,執行HttpClient的execute方法就可以得到執行結果了。返回的HttpResponse消息體結果具體內容是一個InputStream,我們可以根據需要來讀取內容。返回的消息頭則是顯示http操作方法的執行結果,我們可以根據消息頭來判斷請求執行是否正確,結果是否執行完畢以及如果出錯了錯誤的緣由可能是什麼等信息。關於HttpClient的更多實現和應用後面會進一步學習研究。
參考材料