HTTP協議和HttpClient的入門

HTTP協議的發展史沒有了解,是給予請求與響應模式的、無鏈接、無狀態的應用層的協議。php


#HTTP協議
<br/> ##HTTP協議的URL HTTP URL(URL是一種特殊類型的URI,包含了敢於查找某個資源的足夠的信息)的格式以下:html

http://host[":"port][abs_path]
http表示要經過HTTP協議來定位網絡資源;host表示合法的Internet主機域名或者IP地址;port指定一個端口號,爲空則使用缺省端口80;abs_path指定請求資源的URI;若是URL中沒有給出abs_path,那麼當它做爲請求URI時,必須以「/」的形式給出,一般這個工做瀏覽器自動幫咱們完成。java

##HTTP協議的請求和響應體 請求提算法

響應體

下圖是使用HttpWatchPro工具查看到的一個Headers數據庫

Headers觀察

#HttpURLConnection和HttpClient 利用Http協議聯網
<br/> ##HttpURLConnection基本功能的使用apache

使用 HttpURLConnection須要如下 6 個步驟:瀏覽器

  1. 建立 URL
  2. 得到HttpURLConnection 實例
  3. 設置HttpURLConnection 實例
  4. 鏈接HttpURLConnection 實例
  5. 釋放鏈接。不管執行方法是否成功,都必須釋放鏈接
  6. 對獲得後的內容進行處理

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

1.首先使用構造函數獲取URL,URL請求的類別分爲二類,GET與POST請求。兩者的區別在於:服務器

  • get請求能夠獲取靜態頁面,也能夠把參數放在URL字串後面,傳遞給servlet,網絡

  • post與get的不一樣之處在於post的參數不是放在URL字串裏面,而是放在http請求的正文內。

    <!-- lang: java -->

    URL url = new URL("http://192.168.1.151:8080/SHE/think");

2.得到HttpURLConnection 實例

<!-- lang: java -->
 HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();

3.設置HttpURLConnection 實例

  • 設置是否向httpUrlConnection輸出,由於這個是post請求,參數要放在http正文內,所以須要設爲true, 默認狀況下是false;

    <!-- lang: java -->   
     urlConn.setDoOutput(true);
  • 設置是否從httpUrlConnection讀入,默認狀況下是true;

    <!-- lang: java -->   
      urlConn.setDoInput(true);
  • 設置緩存, Post 請求不能使用緩存

    <!-- lang: java -->
      urlConn.setUseCaches(false);
  • 設定請求的方法類型,默認是GET

    <!-- lang: java -->
      urlConn.setRequestMethod("POST");
  • 設置鏈接主機超時(單位:毫秒)

    <!-- lang: java -->
      urlCon.setConnectTimeout(30000);
  • 設置從主機讀取數據超時(單位:毫秒)

    <!-- lang: java -->
      urlCon.setReadTimeout(30000);

-設置GET方法對應HTTP請求中的消息報頭(可選):

<!-- lang: java -->
    httpurlconnection.setRequestProperty("User-Agent",Commons.User_Agent);    
    httpurlconnection.setRequestProperty("Accept",Commons.Accept);    
    httpurlconnection.setRequestProperty("Accept-Charset",Commons.Accept_Charset);    
    httpurlconnection.setRequestProperty("AcceptLanguage",Commons.Accept_Language;    
    httpurlconnection.setRequestProperty("Connection",Commons.Connection);    
    httpurlconnection.setRequestProperty("Keep-Alive",Commons.Keep_Alive);
  • POST請求設定傳送的內容類型是可序列化的java對象 ,若是不設此項,在傳送序列化對象時,當WEB服務默認的不是這種類型時可能拋java.io.EOFException

    <!-- lang: java -->   
      urlConn.setRequestProperty("Content-type","application/x-java-serialized-object");

4.鏈接HttpURLConnection 實例

  • 普通鏈接,connect()

    <!-- lang: java -->
      urlConnection.connect();
  • 2B鏈接,得到輸出流,向服務器輸出數據(不用調用connect())

    <!-- lang: java -->
      String params = "username=sbCode&password=123456";    
      OutputStream outStream = httpUrlConnection.getOutputStream();      
      outStream .write(params.getBytes());
      outStream.flush();

服務器端可經過request.getParameter("username");得到傳入服務器的數據。

  • 文藝鏈接,調用HttpURLConnection鏈接對象的getInputStream()函數, 得到服務器的數據,將內存緩衝區中封裝好的完整的HTTP請求電文發送到服務端。

    <!-- lang: java -->
      InputStream inStream = uRLConnection.getInputStream();

能夠經過int responseCode = urlConnection.getResponseCode();得到服務器的狀態碼,若是爲200就是正常。注意最後關閉流對象

5.釋放鏈接

<!-- lang: java -->
uRLConnection.disconnect();

6.處理得到InputStream

<!-- lang: java -->
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	byte[] data = new byte[1024];
	int len = 0;
	String result = "";
	if(inputStream != null){
		try {
			while((len = inputStream.read(data))!=-1){
				byteArrayOutputStream.write(data,0,len);
			}
			result = new String(byteArrayOutputStream.toByteArray(),encode);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

##HttpClient的入門 <br/> ###HttpClient 功能介紹
如下列出的是 HttpClient 提供的主要的功能:

  • 實現了全部 HTTP 的方法(GET,POST,PUT,HEAD 等)
  • 支持自動轉向
  • 支持 HTTPS 協議
  • 支持代理服務器等

###HttpClient 基本功能的使用

###GET 方法

使用 HttpClient 須要如下 6 個步驟:

  1. 建立 HttpClient 的實例
  2. 建立某種鏈接方法的實例,在這裏是 GetMethod。在 GetMethod 的構造函數中傳入待鏈接的地址
  3. 調用第一步中建立好的實例的 execute 方法來執行第二步中建立好的 method 實例
  4. 讀 response
  5. 釋放鏈接。不管執行方法是否成功,都必須釋放鏈接
  6. 對獲得後的內容進行處理

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

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

    <!-- lang: java -->
      HttpClient httpClient = new HttpClient();
  • 建立GET方法的實例。在GET方法的構造函數中傳入待鏈接的地址便可。用GetMethod將會自動處理轉發過程,若是想要把自動處理轉發過程去掉的話,能夠調用方法setFollowRedirects(false)。

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

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

    <!-- lang: java -->
      byte[] responseBody = method.getResponseBody();
  • 釋放鏈接。不管執行方法是否成功,都必須釋放鏈接。

    <!-- lang: java -->
      method.releaseConnection();
  • 處理內容。在這一步中根據你的須要處理內容,在例子中只是簡單的將內容打印到控制檯。

    <!-- lang: java -->
      System.out.println(new String(responseBody));

下面是程序的完整代碼

<!-- lang: java -->
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
public class GetSample{
  public static void main(String[] args) {
  //構造HttpClient的實例
  HttpClient httpClient = new HttpClient();
  //建立GET方法的實例
  GetMethod getMethod = new GetMethod("http://www.ibm.com");
  //使用系統提供的默認的恢復策略
  getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
    new DefaultHttpMethodRetryHandler());
  try {
   //執行getMethod
   int statusCode = httpClient.executeMethod(getMethod);
   if (statusCode != HttpStatus.SC_OK) {
   System.err.println("Method failed: "+ getMethod.getStatusLine());
   }
   //讀取內容 
   byte[] responseBody = getMethod.getResponseBody();
   //處理內容
   System.out.println(new String(responseBody));
  } catch (HttpException e) {
   //發生致命的異常,多是協議不對或者返回的內容有問題
   System.out.println("Please check your provided http address!");
   e.printStackTrace();
  } catch (IOException e) {
   //發生網絡異常
   e.printStackTrace();
  } finally {
   //釋放鏈接
   getMethod.releaseConnection();
  }
 }
}

###POST方法

根據RFC2616,對POST的解釋以下:POST方法用來向目的服務器發出請求,要求它接受被附在請求後的實體,並把它看成請求隊列(Request-Line)中請求URI所指定資源的附加新子項。POST被設計成用統一的方法實現下列功能:

  • 對現有資源的註釋(Annotation of existing resources)
  • 向電子公告欄、新聞組,郵件列表或相似討論組發送消息
  • 提交數據塊,如將表單的結果提交給數據處理過程
  • 經過附加操做來擴展數據庫

調用HttpClient中的PostMethod與GetMethod相似,除了設置PostMethod的實例與GetMethod有些不一樣以外,剩下的步驟都差很少。在下面的例子中,省去了與GetMethod相同的步驟,只說明與上面不一樣的地方。

<!-- lang: java -->    
String url = "http://www.newsmth.net/bbslogin2.php";
PostMethod postMethod = new PostMethod(url);
// 填入各個表單域的值
NameValuePair[] data = { new NameValuePair("id", "youUserName"),
new NameValuePair("passwd", "yourPwd") };
// 將表單的值放入postMethod中
postMethod.setRequestBody(data);
// 執行postMethod
int statusCode = httpClient.executeMethod(postMethod);
// HttpClient對於要求接受後繼服務的請求,象POST和PUT等不能自動處理轉發
// 301或者302
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || 
statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
    // 從頭中取出轉向的地址
    Header locationHeader = postMethod.getResponseHeader("location");
    String location = null;
    if (locationHeader != null) {
     location = locationHeader.getValue();
     System.out.println("The page was redirected to:" + location);
    } else {
     System.err.println("Location field value is null.");
    }
    return;
}

###使用HttpClient過程當中常見的一些問題 <br/> ###字符編碼

某目標頁的編碼可能出如今兩個地方,第一個地方是服務器返回的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頭中返回的編碼信息衝突,須要用戶本身判斷到底那種編碼類型應該是真正的編碼。

###處理代理服務器

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

<!-- lang: java -->
httpClient.getHostConfiguration().setProxy(hostName,port);

參考資料:
Commons logging包含了各類各樣的日誌API的實現,讀者能夠經過站點獲得詳細的內容
Commons codec包含了一些通常的解碼/編碼算法。包含了語音編碼、十六進制、Base64和URL編碼等,經過站點能夠獲得詳細的內容
HTTPClient的主頁,能夠在這裏獲得關於HttpClient更加詳細的信息

本文多數內容來自這裏,還有這裏

相關文章
相關標籤/搜索