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

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

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

可以抽象為以下圖表結構:

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

同樣可以抽象出如下圖表結構:

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

常見響應頭

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

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