
無(wú)論從事前端還是后端開發(fā),我們都應(yīng)該了解HTTP,HTTP的知識(shí)體系龐大而復(fù)雜,可能用幾篇博客都無(wú)法完全覆蓋,所以本篇只對(duì)實(shí)際應(yīng)用所能涉及到的知識(shí)進(jìn)行介紹。
什么是HTTP
超文本傳輸協(xié)議(HTTP,HyperText Transfer Protocol)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。所有的WWW文件都必須遵守這個(gè)標(biāo)準(zhǔn)。設(shè)計(jì)HTTP最初的目的是為了提供一種發(fā)布和接收HTML頁(yè)面的方法。--來(lái)源:百度百科
基于官方的解釋在百度上可以搜到很多,這里不再贅述。重點(diǎn)在于理解它是一種通訊協(xié)議,HTTP定義了一種規(guī)約,網(wǎng)絡(luò)上的各種終端基于這種規(guī)約,可以進(jìn)行跨地域,跨技術(shù)平臺(tái)的通訊。
Url
我們知道,想要訪問(wèn)一個(gè)網(wǎng)站,需要在瀏覽器地址欄中輸入一串Url,如,我們要訪問(wèn)簡(jiǎn)書http://www.itdecent.cn/。
點(diǎn)擊回車,稍等片刻便可以看到豐富多彩的頁(yè)面,整個(gè)過(guò)程實(shí)際上是由瀏覽器向后臺(tái)服務(wù)器發(fā)送了一個(gè)HTTP請(qǐng)求。服務(wù)器收到請(qǐng)求進(jìn)行相應(yīng)處理后生成一個(gè)響應(yīng),隨后返回至瀏覽器,經(jīng)過(guò)瀏覽器解析呈現(xiàn)信息內(nèi)容。

HTTP通過(guò)Url(統(tǒng)一資源定位符)建立連接和傳輸數(shù)據(jù),Url標(biāo)識(shí)網(wǎng)絡(luò)上某一處資源的地址,我們以一個(gè)常見的GET請(qǐng)求為例,看看其構(gòu)成。

- 協(xié)議部分:訪問(wèn)服務(wù)器所使用的協(xié)議,如http,https,ftp等;
- 域名部分:目標(biāo)主機(jī)的域名,本例中域名是“www.process.com”,也可以使用IP地址。通過(guò)域名,可以幫助你在浩瀚的網(wǎng)絡(luò)世界中快速定位你想訪問(wèn)的目標(biāo)服務(wù)器;
- 資源路徑:域名“/”后面的部分,又稱虛擬目錄。指向是你要訪問(wèn)的目標(biāo)服務(wù)器下某個(gè)資源的路徑;
- 訪問(wèn)參數(shù):“?”后面的部分是訪問(wèn)參數(shù),多個(gè)參數(shù)間使用“&”符連接。
在初步了解Url之后,我們一起來(lái)揭開HTTP的神秘面紗。
互聯(lián)網(wǎng)中,無(wú)時(shí)不刻不在進(jìn)行著數(shù)據(jù)的交換與傳輸,這些傳輸以報(bào)文的形式進(jìn)行。報(bào)文包含了一次傳輸所需要的所有信息。之前提到,HTTP是一種通訊協(xié)議,報(bào)文格式就是協(xié)議中的一部分。兩端只要遵從相同的協(xié)議,就可以進(jìn)行通訊。
Request請(qǐng)求報(bào)文
為了更直觀的理解,我用Chrome瀏覽器自帶的抓包工具,抓取一次Request請(qǐng)求,且看下圖:

可以抽象為以下圖表結(jié)構(gòu):

-
請(qǐng)求行
包含以下三個(gè)部分- 請(qǐng)求方法:HTTP/1.1協(xié)議定義了8種請(qǐng)求方法 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。其中,GET、POST最為常用。在主流的Restful架構(gòu)風(fēng)格中,常用GET表示獲取資源,POST表示新建或更新資源,PUT表示更新資源,DELETE表示刪除資源。
- 請(qǐng)求地址:請(qǐng)求目標(biāo)資源的訪問(wèn)地址,同Url。
- 協(xié)議版本:注明HTTP協(xié)議的版本,本例中使用的是HTTP1.1版本。
-
請(qǐng)求頭
以鍵值對(duì)的形式,注明向服務(wù)器發(fā)起請(qǐng)求的附加信息。(ps:關(guān)于請(qǐng)求頭Header,后面我會(huì)專門介紹) -
空行
請(qǐng)求頭與請(qǐng)求體中的空行是必須存在的,即便第四部分請(qǐng)求體中沒(méi)有數(shù)據(jù)。 -
請(qǐng)求體
可用于存放媒體數(shù)據(jù),通過(guò)請(qǐng)求頭中Content-Type屬性設(shè)置媒體類型信息,可以是HTML,圖片,JSON字符串等,本例的請(qǐng)求體中沒(méi)有數(shù)據(jù)。
Response響應(yīng)報(bào)文
上文提到,當(dāng)服務(wù)器對(duì)接收到的請(qǐng)求進(jìn)行處理后,會(huì)生成一個(gè)響應(yīng)信息返回到瀏覽器。下面我們來(lái)看看響應(yīng)報(bào)文什么樣:

同樣可以抽象出如下圖表結(jié)構(gòu):

響應(yīng)報(bào)文除了第一行與請(qǐng)求報(bào)文不同,其余部分格式一致。所以只對(duì)Response響應(yīng)報(bào)文的第一行“狀態(tài)行”進(jìn)行說(shuō)明。
狀態(tài)行分為協(xié)議版本,響應(yīng)碼,響應(yīng)信息三個(gè)部分:
- 協(xié)議版本:概念與請(qǐng)求行中的一致,用于注明HTTP協(xié)議的版本。
- 響應(yīng)碼:每次請(qǐng)求目標(biāo)服務(wù)器,該目標(biāo)服務(wù)器都會(huì)返回一個(gè)帶有狀態(tài)碼的頭文件。比如,在訪問(wèn)信息正常的情況下,服務(wù)器會(huì)返回200。另外還有我們常見的404狀態(tài)碼。(傳送門:點(diǎn)我了解更多狀態(tài)碼信息)
- 響應(yīng)信息:包含服務(wù)器返回的響應(yīng)信息,本例中因?yàn)檎TL問(wèn),響應(yīng)信息是“OK”。
HTTP Header
無(wú)論是請(qǐng)求還是響應(yīng),客戶端和服務(wù)器之間都需要傳遞附加信息,Header部分作為載體承載這些信息。Header中屬性的格式為 屬性名: 屬性值(注意!冒號(hào)后帶空格),如:
Content-Type: text/plain
Cache-Control: no-cache
以下是Header中常見屬性:
常見請(qǐng)求頭

常見響應(yīng)頭

通俗的講,這些屬性主要用于“帶話兒”,在請(qǐng)求時(shí)告知服務(wù)器,傳輸?shù)膬?nèi)容的長(zhǎng)度,格式,訪問(wèn)者身份信息等,以便進(jìn)行安全保障。實(shí)際上請(qǐng)求頭和響應(yīng)頭有很多通用屬性,這里不一一列舉。(更多內(nèi)容可以點(diǎn)擊:HTTP 頭域大全)。
HTTP Entity
請(qǐng)求體可以存放各種媒體類型的數(shù)據(jù),根據(jù)使用場(chǎng)景不同,請(qǐng)求體的形式也不同,常用的有以下三種
表單提交
我們?cè)谔峤槐韱螘r(shí),form表單的enctype參數(shù)指定了HTTP請(qǐng)求的Content-Type,默認(rèn)情況下enctype = application/x-www-form-urlencoded,如
<form action="/upload" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="param1">
<input type="text" name="param2">
<input type="file" name="file">
</form>
請(qǐng)求頭中Content-Type: application/x-www-form-urlencoded,瀏覽器會(huì)以x-www-form-urlencoded方式將form表單數(shù)據(jù)格式化為key1=value1&key2=value2...形式的字符串。如果使用GET請(qǐng)求,字符串會(huì)被用“?”拼接到Url后作為QueryString,使用POST請(qǐng)求時(shí),字符串則會(huì)被放入請(qǐng)求體,如下圖:
文件分割
某些場(chǎng)景下,提交的表單數(shù)據(jù)可能包括文件,這時(shí)可以將enctype設(shè)置為multipart/form-data,用于上傳文件流,瀏覽器會(huì)按form表單每個(gè)字段或文件將請(qǐng)求體分割成多個(gè)部分。請(qǐng)求頭中Content-Type的屬性值為multipart/form-data; boundary={boundary},{}中為定義的內(nèi)容分隔符。如Content-Type: multipart/form-data; boundary=----hSJb4uI9kw0Snmu9dw,接下來(lái)我們看報(bào)文結(jié)構(gòu):

可以看到,請(qǐng)求體中包含一個(gè)名為“name”的字段和一個(gè)名為hello的txt文件,中間以--{boundary}分割,報(bào)文結(jié)尾處以“--{boundary}”在加上“--”標(biāo)注表示結(jié)束。
上面提到兩種 POST 數(shù)據(jù)方式,不僅受到原生瀏覽器支持,服務(wù)器也能夠良好支持。不過(guò)在移動(dòng)互聯(lián)網(wǎng)大前端時(shí)代,我們可能需要通過(guò)更靈活的方式面對(duì)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
自定類型
在移動(dòng)開發(fā)的場(chǎng)景下,移動(dòng)端在向服務(wù)器傳輸數(shù)據(jù)時(shí),可以將數(shù)據(jù)Bean轉(zhuǎn)化成Json字符串,放入請(qǐng)求體中,以安卓開發(fā)時(shí)使用retrofit2網(wǎng)絡(luò)框架請(qǐng)求為例:
//創(chuàng)建參數(shù)Bean,設(shè)置參數(shù)
Param param = new Param();
param.setParam1(param1);
param.setParam2(param2);
param.setParam3(param3);
Gson gson = new Gson();
//轉(zhuǎn)化Json字符串
String paramStr = gson.toJson(param)
//設(shè)置實(shí)體Content-Type,將Json字符串放入實(shí)體
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),paramStr);
//發(fā)起請(qǐng)求
Observable<DataBean> response = api.sendRequest(body);
最終發(fā)送的請(qǐng)求就是
POST http://www.process.com HTTP/1.1
Content-Type: application/json;charset=utf-8
~ ~ ~ ~ ~ ~ ~ ~ ~ 空行 ~ ~ ~ ~ ~ ~ ~ ~~ ~
{"param1":"abc","param2":"def","param3":"ghk"}
使用Json可以應(yīng)對(duì)復(fù)雜的結(jié)構(gòu)化數(shù)據(jù),自定類型除使用Json外,還可以通過(guò)將Content-Type屬性設(shè)置為application/xml,application/zip,來(lái)存放更多媒體類型。
HTTP RequestMethod
無(wú)論是請(qǐng)求報(bào)文還是響應(yīng)報(bào)文,頭行格式中都有請(qǐng)求方法屬性。在實(shí)際項(xiàng)目中,初學(xué)者頁(yè)時(shí)常搞不清楚這么多請(qǐng)求方法的區(qū)別。先列出8種方法在網(wǎng)上的主流描述,便于直觀了解:
| 序號(hào) | 方法名 | 解釋 |
|---|---|---|
| 1 | GET | 請(qǐng)求指定的頁(yè)面信息,并返回實(shí)體主體。 |
| 2 | POST | 向指定資源提交數(shù)據(jù)進(jìn)行處理請(qǐng)求(例如提交表單或者上傳文件)。數(shù)據(jù)被包含在請(qǐng)求體中。POST請(qǐng)求可能會(huì)導(dǎo)致新的資源的建立和/或已有資源的修改。 |
| 3 | PUT | 從客戶端向服務(wù)器傳送的數(shù)據(jù)取代指定的文檔的內(nèi)容。 |
| 4 | DELETE | 請(qǐng)求服務(wù)器刪除指定的頁(yè)面。 |
| 5 | PATCH | 實(shí)體中包含一個(gè)表,表中說(shuō)明與該URI所表示的原內(nèi)容的區(qū)別。 |
| 6 | OPTIONS | 允許客戶端查看服務(wù)器的性能。 |
| 7 | HEAD | 類似于get請(qǐng)求,只不過(guò)返回的響應(yīng)中沒(méi)有具體的內(nèi)容,用于獲取報(bào)頭。 |
| 8 | TRACE | 回顯服務(wù)器收到的請(qǐng)求,主要用于測(cè)試或診斷。 |
在RESTful風(fēng)格架構(gòu)盛行之前,我們最多用到的是GET和POST,GET執(zhí)行簡(jiǎn)單效率高,但由于GET采用明文拼接請(qǐng)求參數(shù),固安全性較低。POST請(qǐng)求將參數(shù)放入實(shí)體,相對(duì)提高了信息竊取的門檻。另外GET請(qǐng)求會(huì)受到Url長(zhǎng)度限制,無(wú)法應(yīng)對(duì)復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。POST請(qǐng)求則無(wú)此問(wèn)題。
在RESTful風(fēng)格中,GET,POST,PUT,DELETE,分別被抽象出來(lái)對(duì)應(yīng)查,增,改,刪四項(xiàng)操作。
至此,本篇內(nèi)容基本完畢。想深入了解HTTP,需要持續(xù)投入時(shí)間和精力,本文涉獵的每一個(gè)知識(shí)點(diǎn),都可以繼續(xù)展開。同時(shí),無(wú)論你是兩眼發(fā)蒙的職場(chǎng)鮮肉,還是記憶等待喚醒的研發(fā)老司機(jī),筆者都希望能夠從中有所收獲。