HttpClient入門

 HttpClient 功能介紹

  • 實現了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)

  • 支持自動轉向

  • 支持 HTTPS 協議

  • 支持代理服務器等

下面將逐一介紹怎樣使用這些功能。首先,我們必須安裝好 HttpClient

HttpClient 基本功能的使用

GET 方法

使用 HttpClient 需要以下 6 個步驟:

1. 創建 HttpClient 的實例

2. 創建某種連接方法的實例,在這裏是 GetMethod。在 GetMethod 的構造函數中傳入待連接的地址

3. 調用第一步中創建好的實例的 execute 方法來執行第二步中創建好的 method 實例

4. response

5. 釋放連接。無論執行方法是否成功,都必須釋放連接

6. 對得到後的內容進行處理

根據以上步驟,我們來編寫用GET方法來取得某網頁內容的代碼。

  • 大部分情況下 HttpClient 默認的構造函數已經足夠使用。

  1. HttpClient httpClient = new HttpClient(); 
  • 創建GET方法的實例。在GET方法的構造函數中傳入待連接的地址即可。用GetMethod將會自動處理轉發過程,如果想要把自動處理轉發過程去掉的話,可以調用方法setFollowRedirects(false)

  1. GetMethod getMethod = new GetMethod("http://www.ibm.com/"); 
  • 調用實例httpClientexecuteMethod方法來執行getMethod。由於是執行在網絡上的程序,在運行executeMethod方法的時候,需要處理兩個異常,分別是HttpExceptionIOException。引起第一種異常的原因主要可能是在構造getMethod的時候傳入的協議不對,比如不小心將"http"寫成"htp",或者服務器端返回的內容不正常等,並且該異常發生是不可恢復的;第二種異常一般是由於網絡原因引起的異常,對於這種異常 IOException),HttpClient會根據你指定的恢復策略自動試着重新執行executeMethod方法。HttpClient的恢復策略可以自定義(通過實現接口HttpMethodRetryHandler來實現)。通過httpClient的方法setParameter設置你實現的恢復策略,本文中使用的是系統提供的默認恢復策略,該策略在碰到第二類異常的時候將自動重試3次。executeMethod返回值是一個整數,表示了執行該方法後服務器返回的狀態碼,該狀態碼能表示出該方法執行是否成功、需要認證或者頁面發生了跳轉(默認狀態下GetMethod的實例是自動處理跳轉的)等。

  1. //設置成了默認的恢復策略,在發生異常時候將自動重試3次,在這裏你也可以設置成自定義的恢復策略 
  2.  
  3. getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
  4.  
  5.         new DefaultHttpMethodRetryHandler()); 
  6.  
  7. //執行getMethod 
  8.  
  9. int statusCode = client.executeMethod(getMethod); 
  10.  
  11. if (statusCode != HttpStatus.SC_OK) { 
  12.  
  13.   System.err.println("Method failed: " + getMethod.getStatusLine()); 
  14.  
  15.  
  • 在返回的狀態碼正確後,即可取得內容。取得目標地址的內容有三種方法:第一種,getResponseBody,該方法返回的是目標的二進制的byte流;第二種,getResponseBodyAsString,這個方法返回的是String類型,值得注意的是該方法返回的String的編碼是根據系統默認的編碼方式,所以返回的String值可能編碼類型有誤,在本文的"字符編碼"部分中將對此做詳細介紹;第三種,getResponseBodyAsStream,這個方法對於目標地址中有大量數據需要傳輸是最佳的。在這裏我們使用了最簡單的getResponseBody方法。

  1. byte[] responseBody = method.getResponseBody(); 
  • 釋放連接。無論執行方法是否成功,都必須釋放連接。

  1. method.releaseConnection();  
  • 處理內容。在這一步中根據你的需要處理內容,在例子中只是簡單的將內容打印到控制檯。

  1. System.out.println(new String(responseBody));  

下面是程序的完整代碼,這些代碼也可在附件中的test.GetSample中找到。


  1. package test; 
  2.  
  3. import java.io.IOException; 
  4.  
  5. import org.apache.commons.httpclient.*; 
  6.  
  7. import org.apache.commons.httpclient.methods.GetMethod; 
  8.  
  9. import org.apache.commons.httpclient.params.HttpMethodParams; 
  10.  
  11. public class GetSample{ 
  12.  
  13.   public static void main(String[] args) { 
  14.  
  15.   //構造HttpClient的實例 
  16.  
  17.   HttpClient httpClient = new HttpClient(); 
  18.  
  19.   //創建GET方法的實例 
  20.  
  21.   GetMethod getMethod = new GetMethod("http://www.ibm.com"); 
  22.  
  23.   //使用系統提供的默認的恢復策略 
  24.  
  25.   getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
  26.  
  27.     new DefaultHttpMethodRetryHandler()); 
  28.  
  29.   try { 
  30.  
  31.    //執行getMethod 
  32.  
  33.    int statusCode = httpClient.executeMethod(getMethod); 
  34.  
  35.    if (statusCode != HttpStatus.SC_OK) { 
  36.  
  37.     System.err.println("Method failed: " 
  38.  
  39.       + getMethod.getStatusLine()); 
  40.  
  41.    } 
  42.  
  43.    //讀取內容 
  44.  
  45.    byte[] responseBody = getMethod.getResponseBody(); 
  46.  
  47.    //處理內容 
  48.  
  49.    System.out.println(new String(responseBody)); 
  50.  
  51.   } catch (HttpException e) { 
  52.  
  53.    //發生致命的異常,可能是協議不對或者返回的內容有問題 
  54.  
  55.    System.out.println("Please check your provided http address!"); 
  56.  
  57.    e.printStackTrace(); 
  58.  
  59.   } catch (IOException e) { 
  60.  
  61.    //發生網絡異常 
  62.  
  63.    e.printStackTrace(); 
  64.  
  65.   } finally { 
  66.  
  67.    //釋放連接 
  68.  
  69.    getMethod.releaseConnection(); 
  70.  
  71.   } 
  72.  
  73.  } 
  74.  

 

POST方法

調用HttpClient中的PostMethodGetMethod類似,除了設置PostMethod的實例與GetMethod有些不同之外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod相同的步驟,只說明與上面不同的地方,並以登錄清華大學BBS爲例子進行說明。

  • 構造PostMethod之前的步驟都相同,與GetMethod一樣,構造PostMethod也需要一個URI參數,在本例中,登錄的地址是http://www.newsmth.net/bbslogin2.php。在創建了PostMethod的實例之後,需要給method實例填充表單的值,在BBS的登錄表單中需要有兩個域,第一個是用戶名(域名叫id),第二個是密碼(域名叫passwd)。表單中的域用類NameValuePair來表示,該類的構造函數第一個參數是域名,第二參數是該域的值;將表單所有的值設置到PostMethod中用方法setRequestBody。另外由於BBS登錄成功後會轉向另外一個頁面,但是HttpClient對於要求接受後繼服務的請求,比如POSTPUT,不支持自動轉發,因此需要自己對頁面轉向做處理。具體的頁面轉向處理請參見下面的"自動轉向"部分。代碼如下:

 

  1. POST方法 
  2. 調用HttpClient中的PostMethod與GetMethod類似,除了設置PostMethod的實例與GetMethod有些不同之外,剩下的步驟都差不多。在下面的例子中,省去了與GetMethod相同的步驟,只說明與上面不同的地方,並以登錄清華大學BBS爲例子進行說明。 
  3. •   構造PostMethod之前的步驟都相同,與GetMethod一樣,構造PostMethod也需要一個URI參數,在本例中,登錄的地址是http://www.newsmth.net/bbslogin2.php。在創建了PostMethod的實例之後,需要給method實例填充表單的值,在BBS的登錄表單中需要有兩個域,第一個是用戶名(域名叫id),第二個是密碼(域名叫passwd)。表單中的域用類NameValuePair來表示,該類的構造函數第一個參數是域名,第二參數是該域的值;將表單所有的值設置到PostMethod中用方法setRequestBody。另外由於BBS登錄成功後會轉向另外一個頁面,但是HttpClient對於要求接受後繼服務的請求,比如POST和PUT,不支持自動轉發,因此需要自己對頁面轉向做處理。具體的頁面轉向處理請參見下面的"自動轉向"部分。代碼如下: 
  4. String url = "http://www.newsmth.net/bbslogin2.php"
  5. PostMethod postMethod = new PostMethod(url); 
  6. // 填入各個表單域的值 
  7. NameValuePair[] data = { new NameValuePair("id""youUserName"), 
  8. new NameValuePair("passwd""yourPwd") }; 
  9. // 將表單的值放入postMethod中 
  10. postMethod.setRequestBody(data); 
  11. // 執行postMethod 
  12. int statusCode = httpClient.executeMethod(postMethod); 
  13. // HttpClient對於要求接受後繼服務的請求,象POST和PUT等不能自動處理轉發 
  14. // 301或者302 
  15. if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||  
  16. statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { 
  17.     // 從頭中取出轉向的地址 
  18.     Header locationHeader = postMethod.getResponseHeader("location"); 
  19.     String location = null
  20.     if (locationHeader != null) { 
  21.      location = locationHeader.getValue(); 
  22.      System.out.println("The page was redirected to:" + location); 
  23.     } else { 
  24.      System.err.println("Location field value is null."); 
  25.     } 
  26.     return
  27.  
  28. 完整的程序代碼請參見附件中的test.PostSample 

完整的程序代碼請參見附件中的test.PostSample

 

字符編碼

某目標頁的編碼可能出現在兩個地方,第一個地方是服務器返回的http頭中,另外一個地方是得到的html/xml頁面中。

  • http頭的Content-Type字段可能會包含字符編碼信息。例如可能返回的頭會包含這樣子的信息:Content-Type: text/html; charset=UTF-8。這個頭信息表明該頁的編碼是UTF-8,但是服務器返回的頭信息未必與內容能匹配上。比如對於一些雙字節語言國家,可能服務器返回的編碼類型是UTF-8,但真正的內容卻不是UTF-8編碼的,因此需要在另外的地方去得到頁面的編碼信息;但是如果服務器返回的編碼不是UTF-8,而是具體的一些編碼,比如gb2312等,那服務器返回的可能是正確的編碼信息。通過method對象的getResponseCharSet()方法就可以得到http頭中的編碼信息。

  • 對於象xml或者html這樣的文件,允許作者在頁面中直接指定編碼類型。比如在html中會有<meta http-equiv="Content-Type" content="text/html; charset=gb2312"/>這樣的標籤;或者在xml中會有<?xml version="1.0" encoding="gb2312"?>這樣的標籤,在這些情況下,可能與http頭中返回的編碼信息衝突,需要用戶自己判斷到底那種編碼類型應該是真正的編碼。

自動轉向

根據RFC2616中對自動轉向的定義,主要有兩種:301302301表示永久的移走(Moved Permanently),當返回的是301,則表示請求的資源已經被移到一個固定的新地方,任何向該地址發起請求都會被轉到新的地址上。302表示暫時的轉向,比如在服務器端的servlet程序調用了sendRedirect方法,則在客戶端就會得到一個302的代碼,這時服務器返回的頭信息中location的值就是sendRedirect轉向的目標地址。

HttpClient支持自動轉向處理,但是象POSTPUT方式這種要求接受後繼服務的請求方式,暫時不支持自動轉向,因此如果碰到POST方式提交後返回的是301或者302的話需要自己處理。就像剛纔在POSTMethod中舉的例子:如果想進入登錄BBS後的頁面,必須重新發起登錄的請求,請求的地址可以在頭字段location中得到。不過需要注意的是,有時候location返回的可能是相對路徑,因此需要對location返回的值做一些處理纔可以發起向新地址的請求。

另外除了在頭中包含的信息可能使頁面發生重定向外,在頁面中也有可能會發生頁面的重定向。引起頁面自動轉發的標籤是:<meta http-equiv="refresh" content="5; url=http://www.ibm.com/us">。如果你想在程序中也處理這種情況的話得自己分析頁面來實現轉向。需要注意的是,在上面那個標籤中url的值也可以是一個相對地址,如果是這樣的話,需要對它做一些處理後纔可以轉發。

處理HTTPS協議

方法1,取得證書,並導入本地的keystore

方法2,擴展HttpClient類實現自動接受證書

處理代理服務器

HttpClient中使用代理服務器非常簡單,調用HttpClientsetProxy方法就可以,方法的第一個參數是代理服務器地址,第二個參數是端口號。另外HttpClient也支持SOCKS代理。


  1. httpClient.getHostConfiguration().setProxy(hostName,port); 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章