URLConnection和HttpClient的區別

1. CP/IP、Socket、HTTP簡要介紹 TCP/IP 中文名爲傳輸控制協議/因特網互聯協議,又名網絡通信協議,是Internet最基本的協議、Internet國際互聯網絡的基礎,由網絡層的IP協議和傳輸層的TCP協議組成。 Socket 是支持TCP/IP協議的網絡通訊基本操做單元,許多操做系統爲應用程序提供了一套調用接口(API),方便開發者開發網絡程序。注意,socket自己並非協議,只是提供一個針對TCP或UDP的編程接口。 HTTP 協議是一個web服務器和客戶端通訊的超文本傳送協議,是創建在TCP協議上的一個應用層協議。 HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。 HTTP1.0 客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。 HTTP1.1 能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求。java

2. HttpClient和URLConnection HttpClient Apache公司提供的庫,提供高效的、最新的、功能豐富的支持HTTP協議工具包,支持HTTP協議最新的版本和建議,是個很不錯的開源框架,封裝了http的請求,參數,內容體,響應等,擁有衆多API。 URLConnection Sun公司提供的庫,也是Java的標準類庫java.net中的一員,但這個類什麼都沒封裝,用起來很原始,若須要高級功能,則會顯得不太方便,好比重訪問的自定義,會話和cookie等一些高級功能。web

3. 這兩種方式都支持HTTPS協議,以流的形式進行上傳和下載,配置超時時間,IPV6,鏈接池等功能。編程

4. HttpClient的用法 1、執行請求 HttpClient最重要的功能是執行HTTP方法。一個HTTP方法的執行包含一個或多個HTTP請求/HTTP響應交流,一般由HttpClient的內部來處理。用戶提供一個請求對象,HttpClient發送請求到目標服務器,但願服務器返回一個相應的響應對象,或者拋出一個異常(執行失敗)。 一個簡單的請求執行過程的示例:數組

HttpClient httpclient = new DefaultHttpClient();  
HttpGet httpget = new HttpGet("http://localhost/");  
HttpResponse response = httpclient.execute(httpget);  
HttpEntity entity = response.getEntity();  
if (entity != null) {  
    InputStream instream = entity.getContent();  
    int l;  
    byte[] tmp = new byte[2048];  
    while ((l = instream.read(tmp)) != -1) {  
    }  
}

2、用工具封裝Get請求 對比下面兩段代碼,發現用httpClient提供的方法更具可讀性緩存

HttpGet httpget = new HttpGet(  
"http://www.google.com/search?hl=en&q=httpclient&btnG=Google+Search&aq=f&oq=");

HttpClient提供不少工具方法來簡化建立和修改執行URI,例如:服務器

List<NameValuePair> qparams = new ArrayList<NameValuePair>();  
qparams.add(new BasicNameValuePair("q", "httpclient"));  
qparams.add(new BasicNameValuePair("btnG", "Google Search"));  
qparams.add(new BasicNameValuePair("aq", "f"));  
qparams.add(new BasicNameValuePair("oq", null));  
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search",  
URLEncodedUtils.format(qparams, "UTF-8"), null);  
HttpGet httpget = new HttpGet(uri);

3、處理頭部消息 一個HTTP消息能夠包含一系列頭部描述消息的屬性。例如:內容長度、內容類型等。 HttpClient提供方法檢索、添加、刪除、枚舉頭部信息。cookie

HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1,HttpStatus.SC_OK, "OK");  
response.addHeader("Set-Cookie","c1=a; path=/; domain=localhost");  
response.addHeader("Set-Cookie","c2=b; path=/; domain=localhost");  
//獲取header的方法1  
Header h1 = response.getFirstHeader("Set-Cookie");  
Header h2 = response.getLastHeader("Set-Cookie");  
//獲取header的方法2  
HeaderIterator it = response.headerIterator("Set-Cookie");  
while (it.hasNext()) {  
    System.out.println(it.next());  
}  
//獲取header的方法3  
Header[] headers = response.getAllHeaders();  
for (Header header : headers) {  
    System.out.println(header.getName() + " | " + header.getValue());  
}

4、HTTP實體 HTTP規範定義了兩種包裝實體的方法:POST和PUT。響應一般附上內容實體。 HttpClient根據其內容出自何處區分三種類型的實體: streamed(流式):內容從流中得到,或者在運行中產生。流式實體是不可重複生成的。 self-contained(自我包裝式):內容在內存中或經過獨立的鏈接或其它實體中得到。自我包裝式的實體是能夠重複生成和讀取的。常常用於封裝HTTP請求實體。(像ByteArrayEntity或StringEntity)。 wrapping(包裹式):內容從另一個實體中得到。 若是從一個HTTP響應中獲取流式內容,這個區別對於鏈接管理很重要。 若是是應用程序建立並用於發送的請求實體,這個類型區別就沒那麼重要了。 5、使用HTTP實體 使用實體經常使用的一些API,獲得內容類型、內容長度、內容編碼、內容轉換成String或ByteArray、設置分塊(HTTP1.1)。可是,EntityUtils的使用是不鼓勵的,除非實體響應來自一個可信賴的HTTP服務器和已知的有限長度。網絡

myEntity.getContentType()  
myEntity.getContentLength()  
EntityUtils.getContentCharSet(myEntity)  
EntityUtils.toString(myEntity)  
EntityUtils.toByteArray(myEntity)  
myEntity.setChunked(true);

6、獲得實體內容app

HttpGet httpget = new HttpGet("http://localhost/");  
HttpResponse response = httpclient.execute(httpget);  
HttpEntity entity = response.getEntity();  
if (entity != null) {  
    long len = entity.getContentLength();  
    if (len != -1 && len < 2048) {  
        System.out.println(EntityUtils.toString(entity));  
    } else {  
        InputStream instream = entity.getContent();  
        int byteOne = instream.read();  
        int byteTwo = instream.read();  
        //終止請求,該鏈接將不被重用,保證底層的資源被正確釋放  
        httpget.abort();  
    }  
}

7、生成實體內容 HttpClient提供了常見的數據容器,好比字符串,字節數組,輸入流和文件:StringEntity,ByteArrayEntity,InputStreamEntity和FileEntity。框架

File file = new File("somefile.txt");  
FileEntity entity = new FileEntity(file, "text/plain; charset=\"UTF-8\"");  
HttpPost httppost = new HttpPost("http://localhost/action.do");  
httppost.setEntity(entity);

8、HTML表單(UrlEncodedFormEntity) 許多應用程序須要頻繁模擬提交一個HTML表單的過程,好比,爲了來記錄一個Web應用程序或提交輸出數據。HttpClient提供了特殊的實體類UrlEncodedFormEntity來這個知足過程。

List<NameValuePair> formparams = new ArrayList<NameValuePair>();  
formparams.add(new BasicNameValuePair("param1", "value1"));  
formparams.add(new BasicNameValuePair("param2", "value2"));  
//生成的實體內容:param1=value1¶m2=value2  
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8");  
HttpPost httppost = new HttpPost("http://localhost/handler.do");  
httppost.setEntity(entity);

9、響應處理器(ResponseHandler) ResponseHandler可以保證在任何狀況下都會將底層的HTTP鏈接釋放回鏈接管理器。用戶沒必要擔憂HttpClient鏈接佔用系統資源,能夠把注意力集中在處理HTTP響應內容。

HttpClient httpclient = new DefaultHttpClient();  
HttpGet httpget = new HttpGet("http://localhost/");  
ResponseHandler<byte[]> handler = new ResponseHandler<byte[]>() {  
    public byte[] handleResponse(HttpResponse response) throws ClientProtocolException, IOException {  
        HttpEntity entity = response.getEntity();  
        if (entity != null) {  
            return EntityUtils.toByteArray(entity);  
        } else {  
            return null;  
        }  
    }  
};  
byte[] response = httpclient.execute(httpget, handler);

5. URLConnection用法 1、建立HttpURLConnection對象

URL url = new URL("http://localhost:8080/TestHttpURLConnectionPro/index.jsp");   
URLConnection urlConnection = url.openConnection();  
HttpURLConnection httpUrlConnection = (HttpURLConnection) urlConnection;

URL.openConnection()的實現是在java.net.URL類中。

//java.net.URL類裏面的openConnection方法:    
public URLConnection openConnection(Proxy proxy){    
   …    
   return handler.openConnection(this, proxy);   
}

這裏的handler又是什麼呢,跟進去,發現Handler是sun.net.www.protocol.http.Handler這個java類,繼承java.net.URLStreamHandler類,是用來處理http鏈接請求響應的。 繼續跟蹤代碼

//Handler的方法  
protected java.net.URLConnection openConnection(URL u, Proxy p) throws IOException {    
    return new HttpURLConnection(u, p, this);  
}

2、HttpURLConnection參數設置最終發現只是簡單的生成了HttpURLConnection對象,其實最重要的HttpURLConnection就在這裏了,這個是sun.net.www.protocl.http.HttpURLConnection類的對象,繼承java.net.HttpURLConnection。也就是說咱們以後所用的API實現都在sun.net.www.protocl.http.HttpURLConnection這個類裏面。因此你們想要看HttpURLConnection的源碼實現的話,須要到這個類中去查看。 好了,說了這麼多,下面仍是介紹HttpURLConnection經常使用的API的使用吧。 一、設置是否向httpUrlConnection輸出,默認狀況下是false。使用httpUrlConnection.getOutputStream(),把內容輸出到遠程服務器上。

httpUrlConnection.setDoOutput(true);

二、設置是否從httpUrlConnection讀入,默認狀況下是true。使用httpUrlConnection.getInputStream(),從遠程服務器上獲得響應的內容。

httpUrlConnection.setDoInput(true);

三、是否使用緩存。``` httpUrlConnection.setUseCaches(false);

四、設定傳送的內容類型是可序列化的java對象 (若是不設此項,在傳送序列化對象時,當WEB服務默認的不是這種類型時可能拋java.io.EOFException)。

httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");

五、設定請求的方法爲」POST」,默認是GET 。

httpUrlConnection.setRequestMethod("POST");

**3、HttpURLConnection鏈接**

httpUrlConnection.connect();
//此處getOutputStream會隱含的進行connect,因此在開發中不調用上述的connect()也能夠
OutputStream outStrm = httpUrlConnection.getOutputStream();

**4、HttpURLConnection寫數據與發送數據**

// 如今經過輸出流對象構建對象輸出流對象,以實現輸出可序列化的對象。
ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm);
// 向對象輸出流寫出數據,這些數據將存到內存緩衝區中
objOutputStrm.writeObject(new String("我是測試數據"));
// 刷新對象輸出流,將任何字節都寫入潛在的流中(些處爲ObjectOutputStream)
objOutputStm.flush();
// 關閉流對象。此時,不能再向對象輸出流寫入任何數據,先前寫入的數據存在於內存緩衝區中,
// 在調用下邊的getInputStream()函數時才把準備好的http請求正式發送到服務器
objOutputStm.close();
// 調用HttpURLConnection鏈接對象的getInputStream()函數,
// 將內存緩衝區中封裝好的完整的HTTP請求電文發送到服務端。
// <===注意,實際發送請求的代碼段就在這裏
InputStream inStrm = httpConn.getInputStream();

**5、HttpURLConnection注意事項**
1. HttpURLConnection的connect()函數,實際上只是創建了一個與服務器的tcp鏈接,並無實際發送http請求。不管是post仍是get請求,http請求實際上直到HttpURLConnection的getInputStream()這個函數裏面才正式發送出去。因此對outputStream的寫操做,必需要在inputStream的讀操做以前。 

2. 在用POST方式發送URL請求時,URL請求參數的設定順序是重中之重,對connection對象的一切配置(那一堆set函數)都必需要在connect()函數執行以前完成。


功能用法對比
從功能上對比,HttpClient庫要豐富不少,提供了不少工具,封裝了http的請求頭,參數,內容體,響應,還有一些高級功能,代理、COOKIE、鑑權、壓縮、鏈接池的處理。
HttpClient高級功能代碼寫起來比較複雜,對開發人員的要求會高一些,而HttpURLConnection對大部分工做進行了包裝,屏蔽了不須要的細節,適合開發人員直接調用。
另外,HttpURLConnection在2.3版本增長了一些HTTPS方面的改進,4.0版本增長一些響應的緩存。
性能對比
HttpUrlConnection直接支持GZIP壓縮;HttpClient也支持,但要本身寫代碼處理。
HttpUrlConnection直接支持系統級鏈接池,即打開的鏈接不會直接關閉,在一段時間內全部程序可共用;HttpClient固然也能作到,但畢竟不如官方直接系統底層支持好。
HttpUrlConnection直接在系統層面作了緩存策略處理(4.0版本以上),加快了重複請求的速度。
這篇文章對二者的速度作了一個對比,作法是兩個類都使用默認的方法去請求百度的網頁內容,測試結果是使用httpurlconnection耗時47ms,使用httpclient耗時641ms。httpURLConnection在速度有比較明顯的優點,固然這跟壓縮內容和緩存都有直接關係。
將來發展
HttpClient 適用於 web browsers, 他們是可擴展的,而且擁有大量的穩定APIs。可是,在不破壞其兼容性的前提下很難對如此多的APIs作修改。所以,Android 團隊對修改優化Apache HTTP Client表現的並不積極。
HttpURLConnect 是一個通用的、適合大多數應用的輕量級組件。這個類起步比較晚,很容易在主要API上作穩步的改善。可是HttpURLConnection在在Android 2.2及如下版本上存在一些使人厭煩的bug,尤爲是在讀取 InputStream時調用 close()方法,就有可能會致使鏈接池失效了。
Android團隊將來的工做會將更多的時間放在優化HttpURLConnection上,它的API簡單,體積較小,於是很是適用於Android項目。壓縮和緩存機制能夠有效地減小網絡訪問的流量,在提高速度和省電方面也起到了較大的做用。
選用建議
若是一個Android應用須要向指定頁面發送請求,但該頁面並非一個簡單的頁面,只有當用戶已經登陸,並且登陸用戶的用戶名有效時纔可訪問該頁面。若是使用HttpURLConnection來訪問這個被保護的頁面,那麼須要處理的細節就太複雜了。這種狀況建議使用HttpClient。
Android2.3及以上版本建議選用HttpURLConnection,2.2及如下版本建議選用HttpClient。新的應用都建議使用HttpURLConnection。
相關文章
相關標籤/搜索