Android開源框架——OkHttp

An HTTP & HTTP/2 client for Android and Java applications.
一個處理網(wǎng)絡(luò)請求的開源項目,是安卓端最火熱的輕量級框架,由移動支付Square公司貢獻(xiàn)。


1. 知識回顧

1.1 HTTP協(xié)議及特點

HTTP協(xié)議是Hyper Text Transfer Protocol(超文本傳輸協(xié)議)的縮寫衔掸,是用于從萬維網(wǎng)(WWW:World Wide Web)服務(wù)器傳輸超文本到本地瀏覽器的傳送協(xié)議拧抖,它是一種請求/響應(yīng)式的協(xié)議,客戶端在與服務(wù)器端建立連接后稳强,即可向服務(wù)器端發(fā)送請求,這種請求被稱為HTTP請求,服務(wù)器端接收到請求后會做出響應(yīng)祭犯,稱為HTTP響應(yīng)切蟋。

客戶端與服務(wù)器端在HTTP協(xié)議下的交互過程

HTTP協(xié)議是一種基于TCP協(xié)議的通訊協(xié)議统捶。由于TCP協(xié)議提供傳輸控制,按順序組織數(shù)據(jù)和錯誤糾正柄粹,因此HTTP協(xié)議使用TCP協(xié)議而不是UDP協(xié)議喘鸟。

其特點可以總結(jié)為如下幾點:

  1. 簡單快速:客戶向服務(wù)器請求服務(wù)時,只需傳送請求方法和路徑驻右。請求方法常用的有GET什黑、HEAD、POST旺入。每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同兑凿。由于HTTP協(xié)議簡單,使得HTTP服務(wù)器的程序規(guī)模小茵瘾,因而通信速度很快礼华。
  2. 靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對象。正在傳輸?shù)念愋陀蒀ontent-Type加以標(biāo)記拗秘。
  3. 無連接:無連接的含義是限制每次連接只處理一個請求圣絮。服務(wù)器處理完客戶的請求,并收到客戶的應(yīng)答后雕旨,即斷開連接扮匠。采用這種方式可以節(jié)省傳輸時間。
  4. 無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議凡涩。無狀態(tài)是指協(xié)議對于事務(wù)處理沒有記憶能力棒搜。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳活箕,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大力麸。另一方面,在服務(wù)器不需要先前信息時它的應(yīng)答就較快。
  5. 支持B/S及C/S模式克蚂。

1.2 HTTP的工作方式

HTTP協(xié)議定義Web客戶端如何從Web服務(wù)器請求Web頁面闺鲸,以及服務(wù)器如何把Web頁面?zhèn)魉徒o客戶端。HTTP協(xié)議采用了請求/響應(yīng)模型埃叭∶校客戶端向服務(wù)器發(fā)送一個請求報文,請求報文包含請求的方法赤屋、URL立镶、協(xié)議版本、請求頭部和請求數(shù)據(jù)益缎。服務(wù)器以一個狀態(tài)行作為響應(yīng)谜慌,響應(yīng)的內(nèi)容包括協(xié)議的版本、成功或者錯誤代碼莺奔、服務(wù)器信息欣范、響應(yīng)頭部和響應(yīng)數(shù)據(jù)。

  1. 客戶端連接到Web服務(wù)器:一個HTTP客戶端令哟,通常是瀏覽器恼琼,與Web服務(wù)器的HTTP端口(默認(rèn)為80)建立一個TCP套接字連接;
  2. 發(fā)送HTTP請求:通過TCP套接字屏富,客戶端向Web服務(wù)器發(fā)送一個文本的請求報文晴竞。一個請求報文由請求行、請求頭部狠半、空行和請求數(shù)據(jù)4部分組成噩死。
  3. 服務(wù)器接受請求并返回HTTP響應(yīng):Web服務(wù)器解析請求,定位請求資源神年。服務(wù)器將資源復(fù)本寫到TCP套接字已维,由客戶端讀取。一個響應(yīng)由狀態(tài)行已日、響應(yīng)頭部垛耳、空行和響應(yīng)數(shù)據(jù)4部分組成。
  4. 釋放連接TCP連接:若connection 模式為close飘千,則服務(wù)器主動關(guān)閉TCP連接堂鲜,客戶端被動關(guān)閉連接,釋放TCP連接;若connection 模式為keepalive护奈,則該連接會保持一段時間缔莲,在該時間內(nèi)可以繼續(xù)接收請求;
  5. 客戶端瀏覽器解析HTML內(nèi)容:客戶端瀏覽器首先解析狀態(tài)行,查看表明請求是否成功的狀態(tài)代碼霉旗。然后解析每一個響應(yīng)頭酌予,響應(yīng)頭告知以下為若干字節(jié)的HTML文檔和文檔的字符集磺箕。客戶端瀏覽器讀取響應(yīng)數(shù)據(jù)HTML抛虫,根據(jù)HTML的語法對其進(jìn)行格式化,并在瀏覽器窗口中顯示简僧。

1.3 HTTP請求與響應(yīng)

1.3.1 請求

HTTP請求包括:一個請求行建椰,若干請求頭,實體內(nèi)容岛马。

請求行:
  1. 請求方式:post棉姐、get、head啦逆、options伞矩、delete、trace夏志、put乃坤,常用post、get沟蔑;
  2. post湿诊、get區(qū)別:表現(xiàn)在數(shù)據(jù)傳遞上
  • get可在url地址后以?形式帶上交給服務(wù)器的數(shù)據(jù),多個數(shù)據(jù)之間以&分隔瘦材,但數(shù)據(jù)容量不能超過1k;
  • post可在請求的實體中向服務(wù)器發(fā)送請求厅须,傳送數(shù)據(jù)量無限制。
請求頭
  • Accept:告訴服務(wù)器 客戶機(jī)支持的數(shù)據(jù)類型
  • Accept-Charset:告訴服務(wù)器食棕,客戶機(jī)采用的編碼
  • Accept-Encoding:告訴服務(wù)器朗和,客戶機(jī)支持的壓縮格式
  • Host:客戶機(jī)通過這個頭告訴服務(wù)器想訪問的主機(jī)
  • Referer:客戶機(jī)通過這個頭告訴服務(wù)器,它是從哪個資源來訪問服務(wù)器(防盜鏈)
  • User-Agent:告訴服務(wù)器客戶機(jī)的軟件環(huán)境
  • Cookie:可以向服務(wù)器帶數(shù)據(jù)
  • Connection:是否保持長連接簿晓,Keep-Alive表示保持長連接

1.3.2 響應(yīng)

HTTP響應(yīng)頭:一個狀態(tài)行眶拉、若干消息頭、以及實體內(nèi)容抢蚀。

狀態(tài)行:
  1. 格式:HTTP版本號 狀態(tài)碼 原因敘述<CRLF>
    狀態(tài)碼用于表示服務(wù)器對請求的處理結(jié)果镀层,為三位的十進(jìn)制數(shù),響應(yīng)狀態(tài)碼分5類:
  • 100-199皿曲;
  • 200-299
    200:表示服務(wù)器成功處理了客戶端的請求唱逢;
  • 300-399:為完成請求,客戶需進(jìn)一步細(xì)化請求屋休,
    302 表示請求的資源臨時從不同的URI響應(yīng)請求坞古,但請求者應(yīng)繼續(xù)使用原有位置進(jìn)行以后的請求。
    304/307:拿緩存劫樟;
  • 400-499:客戶端請求有錯誤痪枫,常用404织堂,403,
    404:表示服務(wù)器找不到請求的資源奶陈;
    403:客戶端沒有權(quán)限訪問服務(wù)器易阳;
  • 500-599
    500:服務(wù)器端出現(xiàn)錯誤
響應(yīng)頭
  • Location:這個頭配合302狀態(tài)使用,用于告訴客戶機(jī)找誰
  • Server:服務(wù)器通過這個頭告訴瀏覽器服務(wù)器的類型
  • Content-Encoding:服務(wù)器通過這個頭告訴瀏覽器數(shù)據(jù)的壓縮格式
  • Content-Type:服務(wù)器通過這個頭告訴瀏覽器回送數(shù)據(jù)的類型(數(shù)據(jù)類型表示服務(wù)器告訴瀏覽器將怎樣顯示數(shù)據(jù)吃粒,是以圖片顯示潦俺,還是文字顯示)
  • Last-Modified:服務(wù)器通過這個頭瀏覽器告訴當(dāng)前資源緩存時間
  • Refresh:服務(wù)器通過這個頭告訴瀏覽器隔多長時間刷新一次;
  • Content-Disposition:服務(wù)器通過這個頭告訴瀏覽器以下載方式打開數(shù)據(jù)
  • Transfer-Encoding:服務(wù)器通過這個頭告訴瀏覽器數(shù)據(jù)的傳送格式
  • Cache-Control:no-cache

2. OkHttp

OkHttp不僅具有高效的請求效率, 并且提供了很多開箱即用的網(wǎng)絡(luò)疑難雜癥解決方案。

  • 支持HTTP/2徐勃。HTTP/2通過使用多路復(fù)用技術(shù)在一個單獨的TCP連接上支持并發(fā), 通過在一個連接上一次性發(fā)送多個請求來發(fā)送或接收數(shù)據(jù) 事示;
  • 如果HTTP/2不可用, 連接池復(fù)用技術(shù)也可以極大減少延時;
  • 支持GZIP, 可以壓縮下載體積 僻肖;
  • 響應(yīng)緩存可以直接避免重復(fù)請求 肖爵;
  • 會從很多常用的連接問題中自動恢復(fù);
  • 如果您的服務(wù)器配置了多個IP地址, 當(dāng)?shù)谝粋€IP連接失敗的時候, OkHttp會自動嘗試下一個IP臀脏;
  • OkHttp還處理了代理服務(wù)器問題和SSL握手失敗問題劝堪。

使用 OkHttp 無需重寫您程序中的網(wǎng)絡(luò)代碼。OkHttp實現(xiàn)了幾乎和java.net.HttpURLConnection一樣的API谁榜。

2.1 配置方法

在android程序里幅聘,我們一般用Gradle:

implementation 'com.squareup.okhttp3:okhttp:3.9.1'

2.2 一般的使用辦法

  1. 創(chuàng)建一個OkHttpClient對象;
  2. 創(chuàng)建一個Request對象窃植,通過內(nèi)部類Builder調(diào)用生成Request對象帝蒿;
  3. 創(chuàng)建一個Call對象,調(diào)用execute/enqueue巷怜。

2.2.1 Get請求

  1. 先實例化okhttp,構(gòu)建一個request葛超,使用的是get方式,放入一個url地址就可以了延塑,也可以通過Request.Builder設(shè)置更多的參數(shù)绣张。
  2. 然后通過client發(fā)起一個請求,放入隊列。等待任務(wù)完成关带,在Callback中取結(jié)果侥涵。
  3. 通過response.body().string()獲取返回來的字符串。
OkHttpClient client = new OkHttpClient();
        //創(chuàng)建一個Request
        Request request = new Request.Builder()
                .get()
                .url(url)
                .build();
        //通過client發(fā)起請求
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                // String str = response.body().string();
                }
    
            }
        });

2.2.2 Post請求

  • From表單形式
OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormBody.Builder().add("username","xiaoyi").build();
        Request request = new Request.Builder()
                .post(body)
                .url(url).
                build();
        client.newCall(request).enqueue(new Callback() {...});
  • JSON參數(shù)形式
OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        Request request = new Request.Builder()
                .post(body)
                .url(url).
                        build();
        client.newCall(request).enqueue(new Callback() {...});

2.2.3 文件上傳

OkHttpClient client = new OkHttpClient();
        RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), fiDatale);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", "head_img", fileBody)
                .addFormDataPart("name", "xiaoyi").build();

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        client.newCall(request).enqueue(new Callback() {...});

2.2.4 文件下載

OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()){
                    downlodefile(response, Environment.getExternalStorageDirectory().getAbsolutePath(),"text.txt");
                }
            }
        });

2.2.5 Interceptors

Interceptors是Okhttp中的攔截器宋雏,官方介紹攔截器是一個強(qiáng)大的監(jiān)聽器芜飘,可以重寫。

  1. 橙色框內(nèi)是okhttp自帶的Interceptors的實現(xiàn)類磨总,它們都是在call.getResponseWithInterceptorChain()中被添加入 InterceptorChain中嗦明,實際上這幾個Interceptor都是在okhttp3后才被引入,它們非常重要蚪燕,負(fù)責(zé)了重連娶牌、組裝請求頭部奔浅、讀/寫緩存、建立socket連接诗良、向服務(wù)器發(fā)送請求/接收響應(yīng)的全部過程汹桦。

  2. 在okhttp3之前,這些行為都封裝在HttpEngine類中鉴裹。okhttp3之后营勤,HttpEngine已經(jīng)被刪去,取而代之的是這5個Interceptor壹罚,可以說一次網(wǎng)絡(luò)請求中的細(xì)節(jié)被解耦放在不同的Interceptor中,不同Interceptor只負(fù)責(zé)自己的那一環(huán)節(jié)工作(對Request或者Response進(jìn)行獲取/處理)寿羞,使得攔截器模式完全貫穿整個網(wǎng)絡(luò)請求猖凛。

  3. 用戶可以添加自定義的Interceptor,okhttp把攔截器分為應(yīng)用攔截器和網(wǎng)絡(luò)攔截器

 public class OkHttpClient implements Cloneable, Call.Factory {
  final List<Interceptor> interceptors;
  final List<Interceptor> networkInterceptors;
  ......
  }
  • 調(diào)用OkHttpClient.Builder的addInterceptor()可以添加應(yīng)用攔截器绪穆,只會被調(diào)用一次辨泳,可以處理網(wǎng)絡(luò)請求回來的最終Response
  • 調(diào)用addNetworkInterceptor()可以添加network攔截器,處理所有的網(wǎng)絡(luò)響應(yīng)(一次請求如果發(fā)生了redirect 玖院,那么這個攔截器的邏輯可能會被調(diào)用兩次)
  1. Application interceptors與Network Interceptors

參考并感謝:

  1. OkHttp用法
  2. OkHttp使用完全教程
  3. okhttp
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菠红,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子难菌,更是在濱河造成了極大的恐慌试溯,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郊酒,死亡現(xiàn)場離奇詭異遇绞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)燎窘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門摹闽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人褐健,你說我怎么就攤上這事付鹿。” “怎么了蚜迅?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵舵匾,是天一觀的道長。 經(jīng)常有香客問我慢叨,道長纽匙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任拍谐,我火速辦了婚禮烛缔,結(jié)果婚禮上馏段,老公的妹妹穿的比我還像新娘。我一直安慰自己践瓷,他們只是感情好院喜,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晕翠,像睡著了一般喷舀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淋肾,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天硫麻,我揣著相機(jī)與錄音,去河邊找鬼樊卓。 笑死拿愧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的碌尔。 我是一名探鬼主播浇辜,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唾戚!你這毒婦竟也來了柳洋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤叹坦,失蹤者是張志新(化名)和其女友劉穎熊镣,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立由,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡轧钓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锐膜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毕箍。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖道盏,靈堂內(nèi)的尸體忽然破棺而出而柑,到底是詐尸還是另有隱情,我是刑警寧澤荷逞,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布媒咳,位于F島的核電站,受9級特大地震影響种远,放射性物質(zhì)發(fā)生泄漏涩澡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一坠敷、第九天 我趴在偏房一處隱蔽的房頂上張望妙同。 院中可真熱鬧射富,春花似錦、人聲如沸粥帚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芒涡。三九已至柴灯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間费尽,已是汗流浹背赠群。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留旱幼,地道東北人乎串。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像速警,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鸯两,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容