Android學(xué)習(xí) 之 Http Client與HttpURLConnection的區(qū)別

很多Android初學(xué)者在接觸到Http協(xié)議的時(shí)候,估計(jì)都會(huì)在選擇HttpClient還是HttpURLConnection之間,這兩個(gè)都是Android中包含的Http客戶(hù)端類(lèi)。那么,這兩個(gè)有什么區(qū)別呢?
  咳,其實(shí)在之前對(duì)我而言并沒(méi)有區(qū)別,因?yàn)槲移綍r(shí)都是用的開(kāi)源框架比如Async-http-client。
  雖然Android 6.0中已經(jīng)拋棄了HttpClient轉(zhuǎn)而使用OkHttp,不過(guò)既然很多面試都喜歡問(wèn)這個(gè)問(wèn)題,那么還是了解一下吧。


補(bǔ)充

TCP/IP、Socket、Http簡(jiǎn)要介紹

1、TCP/IP中文名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議,又名網(wǎng)絡(luò)通訊協(xié)議,是Internet最基本的協(xié)議、Internet國(guó)際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。

2、Socket是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信基本操作單元,許多操作系統(tǒng)為應(yīng)用程序提供了一套調(diào)用接口(API),方便開(kāi)發(fā)者開(kāi)發(fā)網(wǎng)絡(luò)程序。注意,socket本身并不是協(xié)議,只是提供一個(gè)針對(duì)TCP或UDP的編程接口。

3、HTTP協(xié)議是一個(gè)web服務(wù)器和客戶(hù)端通信的超文本傳送協(xié)議,是建立在TCP協(xié)議上的一個(gè)應(yīng)用層協(xié)議。HTTP連接最顯著的特點(diǎn)是客戶(hù)端發(fā)送的每次請(qǐng)求都需要服務(wù)器回送響應(yīng),在請(qǐng)求結(jié)束后,會(huì)主動(dòng)釋放連接。從建立連接到關(guān)閉連接的過(guò)程稱(chēng)為“一次連接”。

Http 1.0與1.1的區(qū)別

最主要的區(qū)別就是連接時(shí),在1.0中只能1個(gè)單獨(dú)的連接只能處理1次請(qǐng)求,1.1中可以執(zhí)行多個(gè)請(qǐng)求,并且多個(gè)請(qǐng)求可以疊加而不用等待一個(gè)請(qǐng)求結(jié)束再發(fā)送下一個(gè)請(qǐng)求。


背景

Http Client

Apache公司提供的庫(kù),提供高效的、最新的、功能豐富的支持HTTP協(xié)議工具包,支持HTTP協(xié)議最新的版本和建議,是個(gè)很不錯(cuò)的開(kāi)源框架,封裝了Http的請(qǐng)求,參數(shù),內(nèi)容體,響應(yīng)等,擁有眾多API。

HttpURLConnection

Sun公司提供的庫(kù),也是Java的標(biāo)準(zhǔn)類(lèi)庫(kù)java.net中的一員,但這個(gè)類(lèi)什么都沒(méi)封裝,用起來(lái)很原始,若需要高級(jí)功能,則會(huì)顯得不太方便,比如重訪(fǎng)問(wèn)的自定義,會(huì)話(huà)和cookie等一些高級(jí)功能。


區(qū)別

功能上

Http Client適用于web瀏覽器,擁有大量靈活的API,實(shí)現(xiàn)起來(lái)比較穩(wěn)定,且其功能比較豐富,提供了很多工具,封裝了http的請(qǐng)求頭,參數(shù),內(nèi)容體,響應(yīng),還有一些高級(jí)功能,代理、COOKIE、鑒權(quán)、壓縮、連接池的處理。
  但是,正因此,在不破壞兼容性的前提下,其龐大的API也使人難以改進(jìn),因此Android團(tuán)隊(duì)對(duì)于修改優(yōu)化Apache Http Client并不積極。(并在A(yíng)ndroid 6.0中拋棄了Http Client,替換成OkHttp)

HttpURLConnection對(duì)于大部分功能都進(jìn)行了包裝,Http Client的高級(jí)功能代碼會(huì)較復(fù)雜,另外,HttpURLConnection在A(yíng)ndroid 2.3中增加了一些Https方面的改進(jìn)(包括Http Client,兩者都支持https)。且在A(yíng)ndroid 4.0中增加了response cache。

性能上

HttpURLConnection直接支持GZIP壓縮,默認(rèn)添加"Accept-Encoding: gzip"頭字段到請(qǐng)求中,并處理相應(yīng)的回應(yīng),而Http Client雖然支持,但需要自己寫(xiě)代碼處理。
  注意:但在2.3中,由于Http的Content-Length頭字段返回的是壓縮后的大小,直接使用getContentLength()方法得到的數(shù)據(jù)大小是錯(cuò)誤的,應(yīng)該使用InputStream.read()直到返回值是-1為止。

HttpURLConnection直接在系統(tǒng)層面做了緩存策略處理(Android 4.0以上),Http請(qǐng)求將在以下三種中選擇:
  1、完全的cache的response將直接從本地存儲(chǔ)中獲取。因?yàn)椴恍枰W(wǎng)絡(luò)連接,此類(lèi)response可以立即得到。
  2、有條件cache的response必須在Web服務(wù)器驗(yàn)證一下cache的有效性??蛻?hù)端發(fā)送一個(gè)請(qǐng)求,比如“如果/foo.png從昨天起有變化則給我新的圖片” , 服務(wù)端的response要么是更新后的內(nèi)容,要么是304 沒(méi)有修改狀態(tài)碼。如果內(nèi)容是沒(méi)有改變的,就不需要下載了。
  3、沒(méi)有cache的response將從服務(wù)器上獲取。得到這些response之后會(huì)存儲(chǔ)到cache以便將來(lái)使用。

這篇文章中對(duì)兩者的速度做了一個(gè)對(duì)比,做法是兩個(gè)類(lèi)都使用默認(rèn)的方法去請(qǐng)求百度的網(wǎng)頁(yè)內(nèi)容,測(cè)試結(jié)果是使用httpurlconnection耗時(shí)47ms,使用httpclient耗時(shí)641ms。httpURLConnection在速度有比較明顯的優(yōu)勢(shì),當(dāng)然這跟壓縮內(nèi)容和緩存都有直接關(guān)系。


選用

HttpURLConnect是一個(gè)通用的、適合大多數(shù)應(yīng)用的輕量級(jí)組件。這個(gè)類(lèi)起步比較晚,很容易在主要API上做穩(wěn)步的改善。但是HttpURLConnection在在A(yíng)ndroid 2.2及以下版本上存在一些令人厭煩的bug,尤其是在讀取 InputStream時(shí)調(diào)用 close()方法,就有可能會(huì)導(dǎo)致連接池失效了。

因此,在2.2之前的版本,Http Client會(huì)是一個(gè)比較好的選擇,而自2.3起,HttpURLConnection將是最佳選擇,其API簡(jiǎn)單,小巧,非常適合于A(yíng)ndroid。透明的壓縮及response cache減少了網(wǎng)絡(luò)流量,改進(jìn)了網(wǎng)絡(luò)速度,也就更省電。

在Volley框架的源碼中,會(huì)發(fā)現(xiàn)它在Http請(qǐng)求的使用上也是如此,在A(yíng)ndroid 2.3及以上的版本,使用的是HttpURLConnection,而在A(yíng)ndroid 2.2及以下版本,使用的是HttpClient。


最后一點(diǎn)小拓展

在開(kāi)頭說(shuō)過(guò),之前的項(xiàng)目中我使用的是Async-http-client,當(dāng)在項(xiàng)目版本中加上Android 23之后,會(huì)出現(xiàn)某些類(lèi)找不到的錯(cuò)誤。雖然從名字上就能看出來(lái)……然而還是讓我們來(lái)挖挖看為什么吧?

當(dāng)通過(guò)get請(qǐng)求的時(shí)候,一般是如此調(diào)用的

AsyncHttpClient client = new AsyncHttpClient();
client.get(url, mAsyncHttpResponseHandler);

直接從get方法點(diǎn)進(jìn)去后會(huì)發(fā)現(xiàn)如此:

public RequestHandle get(String url, ResponseHandlerInterface responseHandler) {
  return get(null, url, null, responseHandler);
}

好像是直接調(diào)用另一個(gè)方法呢?再網(wǎng)上追一下看看:

public RequestHandle get(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler) {
  return sendRequest(httpClient, httpContext, new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params)), null, responseHandler, context);
}

哎,有同學(xué)發(fā)現(xiàn)了沒(méi),在這里有一個(gè)

new HttpGet(getUrlWithQueryString(isUrlEncodingEnabled, url, params))

別急,再看看另外幾個(gè)get方法:

public RequestHandle get(String url, RequestParams params, ResponseHandlerInterface responseHandler) {
  return get(null, url, params, responseHandler);
}

public RequestHandle get(Context context, String url, ResponseHandlerInterface responseHandler) {
  return get(context, url, null, responseHandler);
}

有沒(méi)有眼熟?對(duì)!都是調(diào)用了這個(gè)方法。

public RequestHandle get(Context context, String url, RequestParams params, ResponseHandlerInterface responseHandler)

因此,也就能解釋為什么Async-http-client在A(yíng)ndroid 23中會(huì)無(wú)法使用了。


參考資料

HttpClient和HttpURLConnection的區(qū)別

HttpClient和HttpURLConnection的使用和區(qū)別(上)

HttpClient和HttpURLConnection的使用和區(qū)別(下)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容