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)切蟋。
HTTP協(xié)議是一種基于TCP協(xié)議的通訊協(xié)議统捶。由于TCP協(xié)議提供傳輸控制,按順序組織數(shù)據(jù)和錯誤糾正柄粹,因此HTTP協(xié)議使用TCP協(xié)議而不是UDP協(xié)議喘鸟。
其特點可以總結(jié)為如下幾點:
- 簡單快速:客戶向服務(wù)器請求服務(wù)時,只需傳送請求方法和路徑驻右。請求方法常用的有GET什黑、HEAD、POST旺入。每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同兑凿。由于HTTP協(xié)議簡單,使得HTTP服務(wù)器的程序規(guī)模小茵瘾,因而通信速度很快礼华。
- 靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對象。正在傳輸?shù)念愋陀蒀ontent-Type加以標(biāo)記拗秘。
- 無連接:無連接的含義是限制每次連接只處理一個請求圣絮。服務(wù)器處理完客戶的請求,并收到客戶的應(yīng)答后雕旨,即斷開連接扮匠。采用這種方式可以節(jié)省傳輸時間。
- 無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議凡涩。無狀態(tài)是指協(xié)議對于事務(wù)處理沒有記憶能力棒搜。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳活箕,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大力麸。另一方面,在服務(wù)器不需要先前信息時它的應(yīng)答就較快。
- 支持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ù)。
- 客戶端連接到Web服務(wù)器:一個HTTP客戶端令哟,通常是瀏覽器恼琼,與Web服務(wù)器的HTTP端口(默認(rèn)為80)建立一個TCP套接字連接;
- 發(fā)送HTTP請求:通過TCP套接字屏富,客戶端向Web服務(wù)器發(fā)送一個文本的請求報文晴竞。一個請求報文由請求行、請求頭部狠半、空行和請求數(shù)據(jù)4部分組成噩死。
- 服務(wù)器接受請求并返回HTTP響應(yīng):Web服務(wù)器解析請求,定位請求資源神年。服務(wù)器將資源復(fù)本寫到TCP套接字已维,由客戶端讀取。一個響應(yīng)由狀態(tài)行已日、響應(yīng)頭部垛耳、空行和響應(yīng)數(shù)據(jù)4部分組成。
- 釋放連接TCP連接:若connection 模式為close飘千,則服務(wù)器主動關(guān)閉TCP連接堂鲜,客戶端被動關(guān)閉連接,釋放TCP連接;若connection 模式為keepalive护奈,則該連接會保持一段時間缔莲,在該時間內(nèi)可以繼續(xù)接收請求;
- 客戶端瀏覽器解析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)容岛马。
請求行:
- 請求方式:post棉姐、get、head啦逆、options伞矩、delete、trace夏志、put乃坤,常用post、get沟蔑;
- 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)行:
- 格式: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 一般的使用辦法
- 創(chuàng)建一個OkHttpClient對象;
- 創(chuàng)建一個Request對象窃植,通過內(nèi)部類Builder調(diào)用生成Request對象帝蒿;
- 創(chuàng)建一個Call對象,調(diào)用execute/enqueue巷怜。
2.2.1 Get請求
- 先實例化okhttp,構(gòu)建一個request葛超,使用的是get方式,放入一個url地址就可以了延塑,也可以通過Request.Builder設(shè)置更多的參數(shù)绣张。
- 然后通過client發(fā)起一個請求,放入隊列。等待任務(wù)完成关带,在Callback中取結(jié)果侥涵。
- 通過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)聽器芜飘,可以重寫。
橙色框內(nèi)是okhttp自帶的Interceptors的實現(xiàn)類磨总,它們都是在call.getResponseWithInterceptorChain()中被添加入 InterceptorChain中嗦明,實際上這幾個Interceptor都是在okhttp3后才被引入,它們非常重要蚪燕,負(fù)責(zé)了重連娶牌、組裝請求頭部奔浅、讀/寫緩存、建立socket連接诗良、向服務(wù)器發(fā)送請求/接收響應(yīng)的全部過程汹桦。
在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ò)請求猖凛。
用戶可以添加自定義的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)用兩次)
- Application interceptors與Network Interceptors