轉自:點擊打開連接java
相信不少Android開發者碰到涉及到Http協議的需求時,都和我同樣在猶豫是使用HttpClient仍是使用HttpURLConnection呢。我在網上也搜索了不少文章,來分析二者的區別。接下來咱們就剖析一下這兩個網絡開源庫,分別從背景、用法、相同點、區別這幾點來入手分析。web
TCP/IP、Socket、HTTP簡要介紹編程
TCP/IP中文名爲傳輸控制協議/因特網互聯協議,又名網絡通信協議,是Internet最基本的協議、Internet國際互聯網絡的基礎,由網絡層的IP協議和傳輸層的TCP協議組成。數組
Socket是支持TCP/IP協議的網絡通訊基本操做單元,許多操做系統爲應用程序提供了一套調用接口(API),方便開發者開發網絡程序。注意,socket自己並非協議,只是提供一個針對TCP或UDP的編程接口。服務器
HTTP協議是一個web服務器和客戶端通訊的超文本傳送協議,是創建在TCP協議上的一個應用層協議。
HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。cookie
HTTP1.0
客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。網絡
HTTP1.1
能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求。app
HttpClient框架
Apache公司提供的庫,提供高效的、最新的、功能豐富的支持HTTP協議工具包,支持HTTP協議最新的版本和建議,是個很不錯的開源框架,封裝了http的請求,參數,內容體,響應等,擁有衆多API。dom
HttpURLConnection
Sun公司提供的庫,也是Java的標準類庫java.net中的一員,但這個類什麼都沒封裝,用起來很原始,若須要高級功能,則會顯得不太方便,好比重訪問的自定義,會話和cookie等一些高級功能。
這兩種方式都支持HTTPS協議,以流的形式進行上傳和下載,配置超時時間,IPV6,鏈接池等功能。
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) { } }
對比下面兩段代碼,發現用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);
一個HTTP消息能夠包含一系列頭部描述消息的屬性。例如:內容長度、內容類型等。
HttpClient提供方法檢索、添加、刪除、枚舉頭部信息。
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()); }
HTTP規範定義了兩種包裝實體的方法:POST和PUT。響應一般附上內容實體。
HttpClient根據其內容出自何處區分三種類型的實體:
streamed(流式):內容從流中得到,或者在運行中產生。流式實體是不可重複生成的。
self-contained(自我包裝式):內容在內存中或經過獨立的鏈接或其它實體中得到。自我包裝式的實體是能夠重複生成和讀取的。常常用於封裝HTTP請求實體。(像ByteArrayEntity或StringEntity)。
wrapping(包裹式):內容從另一個實體中得到。
若是從一個HTTP響應中獲取流式內容,這個區別對於鏈接管理很重要。
若是是應用程序建立並用於發送的請求實體,這個類型區別就沒那麼重要了。
使用實體經常使用的一些API,獲得內容類型、內容長度、內容編碼、內容轉換成String或ByteArray、設置分塊(HTTP1.1)。可是,EntityUtils的使用是不鼓勵的,除非實體響應來自一個可信賴的HTTP服務器和已知的有限長度。
myEntity.getContentType() myEntity.getContentLength() EntityUtils.getContentCharSet(myEntity) EntityUtils.toString(myEntity) EntityUtils.toByteArray(myEntity) myEntity.setChunked(true);
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(); } }
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);
許多應用程序須要頻繁模擬提交一個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);
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);
HttpClient還提供了不少高級的特性,如:鏈接管理、狀態管理、認證管理、客戶服務等。這裏只介紹了一些基礎的用法,有時間好好研究一下,再專門寫一篇關於HttpClient的博客。