目錄
HTTP協(xié)議是很基礎(chǔ)但又很容易被忽略的知識。本篇文章整理了HTTP協(xié)議相關(guān)的基礎(chǔ)知識點(diǎn),適合入門學(xué)習(xí)的同學(xué)。
網(wǎng)絡(luò)基礎(chǔ)
計(jì)算機(jī)網(wǎng)絡(luò)協(xié)十分復(fù)雜,為了讓復(fù)雜的網(wǎng)絡(luò)簡單化,專家們對網(wǎng)絡(luò)協(xié)議進(jìn)行了分層。
常見的兩種分層方式:
-
OSI模型 -
TCP/IP協(xié)議
OSI 模型
OSI模型(Open System Interconnection,OSI/RM,Open Systems Interconnection Reference Model),即開放式通信系統(tǒng)互聯(lián)參考模型,是國際標(biāo)準(zhǔn)化組織(ISO)提出的一個試圖使各種計(jì)算機(jī)在世界范圍內(nèi)互連為網(wǎng)絡(luò)的標(biāo)準(zhǔn)框架。
OSI將[計(jì)算機(jī)網(wǎng)絡(luò)體系結(jié)構(gòu)(architecture)劃分為以下七層:
| 分層 | 每層的操作 |
|---|---|
| 應(yīng)用層 | 在數(shù)據(jù)前面加首部,首部包括數(shù)據(jù)內(nèi)容、源地址和目標(biāo)地址,同時也會處理異常的反饋信息。 |
| 表示層 | 將特有的數(shù)據(jù)格式轉(zhuǎn)換為通用的數(shù)據(jù)格式,同時也會加上表示層的首部信息以供解析。 |
| 會話層 | 對何時連接,以何種方式連接,連接多久,何時斷開等做記錄。同時也會加會話層的首部信息。 |
| 傳輸層 | 建立連接,斷開連接,確認(rèn)數(shù)據(jù)是否發(fā)送成功和執(zhí)行失敗重發(fā)任務(wù)。 |
| 網(wǎng)絡(luò)層 | 負(fù)責(zé)將數(shù)據(jù)發(fā)到目標(biāo)地址,也包含首部信息。 |
| 數(shù)據(jù)鏈路層 | 通過物理的傳輸介質(zhì)實(shí)現(xiàn)數(shù)據(jù)的傳輸。 |
| 物理層 | 將0/1轉(zhuǎn)換成物理的傳輸介質(zhì),通過MAC地址進(jìn)行傳輸。 |
TCP/IP 協(xié)議
TCP/IP協(xié)議(Transmission Control Protocol/Internet Protocol),即傳輸控制協(xié)議因特網(wǎng)互聯(lián)協(xié)議,又名網(wǎng)絡(luò)通訊協(xié)議,是Internet最基本的協(xié)議、Internet國際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。TCP/IP 定義了電子設(shè)備如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。
TCP/IP 四層結(jié)構(gòu)
| 分層 | 每層的操作 |
|---|---|
| 應(yīng)用層 | 提供應(yīng)用服務(wù)。協(xié)議:HTTP,F(xiàn)TP,SSH |
| 傳輸層 | 讓應(yīng)用程序之間實(shí)現(xiàn)通信。協(xié)議:TCP,UDP |
| 網(wǎng)絡(luò)層 | 該層核心是IP協(xié)議,基于IP地址轉(zhuǎn)發(fā)數(shù)據(jù)包。 |
| 鏈路層 | 負(fù)責(zé)接收IP數(shù)據(jù)包并通過網(wǎng)絡(luò)發(fā)送,或者從網(wǎng)絡(luò)上接收物理幀,抽出IP數(shù)據(jù)包,交給網(wǎng)絡(luò)層 |
OSI模型與TCP/IP協(xié)議關(guān)系

上圖列出了OSI與TCP/IP分層之間的大致關(guān)系。可以看出,OSI與TCP/IP在分層模塊上稍有區(qū)別,OSI參考模型注重通信協(xié)議必要的功能是什么,而TCP/IP更強(qiáng)調(diào)在計(jì)算機(jī)上實(shí)現(xiàn)協(xié)議應(yīng)該開發(fā)哪種程序。
OSI參考模型并沒有得到普及。TCP/IP協(xié)議被廣泛應(yīng)用,今天主角HTTP屬于TCP/IP協(xié)議。
HTTP介紹
HTTP(HyperText Transfer Protocol, 超文本傳輸協(xié)議)是互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一種網(wǎng)絡(luò)協(xié)議。HTTP 協(xié)議是 TCP/IP 協(xié)議模型的子集,屬于應(yīng)用層協(xié)議。
客戶端與服務(wù)端通信流程
HTTP協(xié)議和TCP/IP協(xié)議族內(nèi)的其他眾多協(xié)議相同,用于客戶端與服務(wù)端之間通信。
請求訪問文本或圖片資源的一端成為客戶端,提供資源響應(yīng)的一端為服務(wù)端。

上圖為客戶端與服務(wù)端交互的流程??蛻舳税l(fā)送請求信息,服務(wù)端返回響應(yīng)信息,一來一回完成了一次HTTP通信。
使用Cookie、Session管理狀態(tài)
HTTP協(xié)議是無狀態(tài)的,它不會記錄之前請求的狀態(tài)。比如,第一次和服務(wù)器交互登錄成功后,第二次發(fā)送請求服務(wù)器仍然不知道這是哪個用戶。Cookie和Session出現(xiàn)就是為了解決這個問題。
Cookie
第一次和服務(wù)器交互登錄成功后,服務(wù)器會把用戶的標(biāo)識存到Cookie中返回給瀏覽器。第二次請求,客戶端帶上Cookie發(fā)送給服務(wù)端,服務(wù)端收到Cookie就知道是哪個用戶請求了。
Cookie儲存在客戶端,不同瀏覽器對儲存大小有不同限制,一般不超過4KB。因此Cookie適合儲存少量數(shù)據(jù)。
Session
Session和Cookie的作用類似,都可以做用戶的狀態(tài)管理。Session儲存在服務(wù)端,儲存的大小和數(shù)據(jù)形式不受限制。
Cookie和Session兩者的區(qū)別在本文常見問題小節(jié)。
HTTP報(bào)文結(jié)構(gòu)
客戶端和服務(wù)端之間交互的信息被稱為HTTP報(bào)文??蛻舳说腍TTP報(bào)文叫做請求報(bào)文,服務(wù)端的叫做響應(yīng)報(bào)文。
HTTP 報(bào)文本身是由多行(用 CR+LF 作換行符)數(shù)據(jù)構(gòu)成的字符串文本。
下面兩段代碼是真實(shí)的報(bào)文數(shù)據(jù),先看一下真實(shí)報(bào)文,理解報(bào)文結(jié)構(gòu)會容易一些。
GET / HTTP/1.1
Host: www.lizhengyang.cn
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: SESSION=t20l97i9pgi9kosj5t9cbil3nm
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 10 Sep 2018 07:19:49 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: blade-2.0.6-BETA
Content-Encoding: gzip
<!DOCTYPE html>
<html>
//此處省略具體HTML數(shù)據(jù)
</html>
這里的報(bào)文數(shù)據(jù)是抓包拿來的,具體怎樣抓取HTTP報(bào)文請看另一篇文章:【網(wǎng)絡(luò)學(xué)習(xí)筆記】使用Wireshark抓取HTTP報(bào)文
請求報(bào)文

請求行
請求行包括:請求方法、URI、HTTP協(xié)議版本
請求方法
| 名稱 | 描述 | 最低支持協(xié)議版本 |
|---|---|---|
| GET | 請求服務(wù)器上的某一資源。 | 1.0 |
| POST | 向指定資源提交數(shù)據(jù)進(jìn)行處理請求,數(shù)據(jù)包含在請求體中。 | 1.0 |
| HEAD | 用于確認(rèn)URI的有效性及資源更新的日期時間,不返回報(bào)文主體,只返回報(bào)文文首部。 | 1.0 |
| PUT | 向用來傳輸文件,將文件內(nèi)容放進(jìn)報(bào)文主體中,保存到URI指定位置上。 | 1.1 |
| DELETE | 與PUT相反,請求URI刪除指定資源。 | 1.1 |
| OPTIONS | 查詢針對請求URI指定的資源支持的方法。 | 1.1 |
| TRACE | 用于追蹤路徑。發(fā)送請求時,首部字段Max-Forwards會指定一個數(shù)值,每經(jīng)過一個服務(wù)器之后,該數(shù)值減1。當(dāng)該數(shù)值為0時,停止傳輸,最后接收到的服務(wù)器響應(yīng)。 | 1.1 |
| CONNECT | 用于在與代理服務(wù)器通信時建立隧道,實(shí)現(xiàn)用隧道協(xié)議進(jìn)行TCP通信。 | 1.1 |
GET和POST方法在工作中比較常用。
GET:
- 常用來查詢數(shù)據(jù)
- 請求參數(shù)包含在URL里面
- 在瀏覽器中對請求參數(shù)有長度限制
POST:
- 常用來提交數(shù)據(jù)
- 請求參數(shù)在請求體中
- 對參數(shù)大小沒有長度限制
POST比GET更安全?
- 在瀏覽器中訪問網(wǎng)址發(fā)送GET請求,請求參數(shù)會附加在網(wǎng)址后面很容被別人看見。POST請求不會把明文參數(shù)顯示在地址中。從這方面來砍GET比POST安全。
- 如果HTTP請求不配置HTTPS證書,不管是POST請求還是GET請求,所有的參數(shù)都會明文在網(wǎng)絡(luò)上傳輸,容易被別人查看甚至篡改。從整體來看,不配置安全證書,POST和GET請求都是不安全的。
URI
URI(Uniform Resource Identifier)統(tǒng)一資源標(biāo)識符,用來標(biāo)識某一互聯(lián)網(wǎng)資源名稱。URI和URL長得很像,容易混淆,在本文最后常見問題中有兩者的差別。
HTTP協(xié)議版本
HTTP主要有三個大版本:HTTP/1.0、HTTP/1.1、HTTP/2.0 。在本文最后常見問題中有版本差異的講解。
請求頭
請求頭由多個鍵值對組成,如:
Host: www.lizhengyang.cn
Connection: keep-alive
這些鍵值被稱為首部字段。具體首部字段內(nèi)容請查看本文HTTP首部字段詳解小節(jié)
空行
HTTP報(bào)文中把第一個出現(xiàn)的空行當(dāng)做分隔符,空行下面就是報(bào)文主體。
請求報(bào)文主體
使用POST方法提交的數(shù)據(jù)必須放在報(bào)文主體中,協(xié)議沒有規(guī)定提交的數(shù)據(jù)使用什么傳輸格式,實(shí)際開發(fā)中客戶端和服務(wù)端可以自己決定傳輸?shù)母袷健?/p>
常見的傳輸格式:
- application/x-www-form-urlencoded
這應(yīng)該是最常見的POST數(shù)據(jù)傳輸格式了。數(shù)據(jù)格式為“KEY=VALUE”鍵值對,多組數(shù)據(jù)中間用“&”符號連接。請求報(bào)文如下:
//刪減了無關(guān)信息
POST http://lizhengyang.cn HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8
title=你好&code=008
注意請求頭字段Content-Type的值為application/x-www-form-urlencoded
-
application/json
傳輸JSON格式的數(shù)據(jù),請求報(bào)文如下:
//刪減了無關(guān)信息 POST http://lizhengyang.cn HTTP/1.1 Content-Type:application/json;charset=utf-8 {"title":"你好","code":80}
注意請求頭字段Content-Type的值為application/json
響應(yīng)報(bào)文

狀態(tài)行
狀態(tài)行包括:HTTP協(xié)議版本、狀態(tài)碼、狀態(tài)碼描述
狀態(tài)碼類型
| 類別 | 原因短語 | |
|---|---|---|
| 1XX | Informational(信息性狀態(tài)碼) | 接收的請求正在處理 |
| 2XX | Success(成功狀態(tài)碼) | 請求正常處理完畢 |
| 3XX | Redirection(重定向狀態(tài)碼) | 需要進(jìn)行附加操作以完成請求 |
| 4XX | Client Error(客戶端錯誤狀態(tài)碼) | 服務(wù)器無法處理請求 |
| 5XX | Server Error(服務(wù)器錯誤狀態(tài)碼) | 服務(wù)器處理請求出錯 |
常見的狀態(tài)碼
| 狀態(tài)碼 | 描述 |
|---|---|
| 200 OK | 請求成功 |
| 304 Not Modified | 所請求的資源未修改,服務(wù)器不會返回任何資源??蛻舳送ǔ彺嬖L問過的資源,通過提供一個頭信息指出客戶端希望只返回在指定日期之后修改的資源 |
| 403 Forbidden | 服務(wù)器理解請求客戶端的請求,但是拒絕執(zhí)行此請求 |
| 404 Not Found | 服務(wù)器無法根據(jù)客戶端的請求找到資源 |
| 500 Internal Server Error | 服務(wù)器內(nèi)部錯誤,無法完成請求 |
響應(yīng)頭
格式同請求頭。
空行
作用同請求報(bào)文中空行。
響應(yīng)報(bào)文主體
常用的傳輸格式除了請求報(bào)文主體中的兩種格式外,還有text/html,HTML網(wǎng)頁就是采用的這種格式
HTTP首部字段詳解
HTTP首部字段根據(jù)實(shí)際用途為三種類型:
- 通用首部字段。請求報(bào)文和響應(yīng)報(bào)文兩方都會使用的首部
- 請求首部字段。從客戶端向服務(wù)器端發(fā)送請求報(bào)文時使用的首部。
- 響應(yīng)首部字段。從服務(wù)器端向客戶端返回響應(yīng)報(bào)文時使用的首部。
- 實(shí)體首部字段。針對請求報(bào)文和響應(yīng)報(bào)文的實(shí)體部分使用的首部
另外還有一些拓展首部字段,沒有在HTTP/1.1中定義,但使用頻率很高。比如:Cookie、Set-Cookie等字段。
通用首部字段

請求首部字段

響應(yīng)首部字段

實(shí)體首部字段

拓展首部字段
Set-Cookie
用來由服務(wù)器端向客戶端發(fā)送cookie
Set-Cookie: name=zhengyang;Domain=lizhengyang.cn;Path=/;Expires=Mon, 10 Sep 2018 07:19:49 GMT; Secure; HttpOnly
Set-Cookie字段的屬性
| 字段 | 屬性 |
|---|---|
| NAME=VALUE | 賦予 Cookie 的名稱和其值(必須項(xiàng)) |
| expires=DATE | 指定瀏覽器可發(fā)送 Cookie 的有效期(若不指定則默認(rèn)為瀏覽器關(guān)閉為止) |
| path=PATH | 將服務(wù)器上的文件目錄作為 Cookie 的適用對象(若不指定則默認(rèn)為文檔所在的文件目錄) |
| domain=域名 | 作為 Cookie 適用對象的域名(若不指定則默認(rèn)為創(chuàng)建 Cookie 的服務(wù)器的域名) |
| Secure | 僅在 HTTPS 安全通信時才會發(fā)送 Cookie |
| HttpOnly | 加以限制,使 Cookie 不能被 JavaScript 腳本訪問。主要目的是為防止跨站腳本攻擊對 Cookie 的信息竊取。 |
Cookie
客戶端向服務(wù)端發(fā)送緩存的Cookie
Cookie:code=0;id=888;
常見問題
uri與url的區(qū)別?
URI和URL在視覺上兩者很相似,在含義上兩者同樣很相似,經(jīng)常讓人傻傻分不清楚。
概念
- URI(Uniform Resource Identifier)統(tǒng)一資源標(biāo)識符,用來標(biāo)識某一互聯(lián)網(wǎng)資源名稱,強(qiáng)調(diào)資源的名稱。
- URL(Uniform Resource Locator)統(tǒng)一資源定位符,用來從互聯(lián)網(wǎng)上獲得某一個資源,強(qiáng)調(diào)資源訪問。
理解
北京市 海淀區(qū) 中關(guān)村 XXX大廈 N層888室 張三 (這是一個虛擬的收件地址)
- URL對應(yīng)著整個收件地址。通過收件地址能聯(lián)系到一個人,通過URL能訪問一個文件,是一個道理。
- URI對應(yīng)著收件人姓名張三。在
北京市 海淀區(qū) 中關(guān)村 XXX大廈 N層888室大喊張三就能找到張三本人,但在河北喊破嗓子也找不到北京市的那個張三。
關(guān)系
URL是URI的子集,所有的URL都是URI,但不是所有的URI都是URL。
cookie與session的區(qū)別
| 對比 | Cookie | Session |
|---|---|---|
| 儲存位置 | 儲存在客戶端 | 儲存在服務(wù)器 |
| 安全性 | 不安全 | 安全 |
| 有效期 | 長 | 短 |
| 對服務(wù)器壓力 | 小 | 大 |
HTTP/1.1、HTTP/2.0版本特性
在建立 HTTP 標(biāo)準(zhǔn)規(guī)范時,制訂者主要想把 HTTP 當(dāng)作傳輸 HTML文檔的協(xié)議。隨著互聯(lián)網(wǎng)的發(fā)展,web用途更具有多樣性,HTTP也廣泛應(yīng)用到移動端,我們對HTTP性能的要求也越來越高。為了適應(yīng)新時代的要求,HTTP協(xié)議逐漸從1.0版本迭代到了1.1、2.0。
HTTP/1.1 特性
緩存處理
在HTTP1.0中主要使用header里的If-Modified-Since,Expires來做為緩存判斷的標(biāo)準(zhǔn),HTTP1.1則引入了更多的緩存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供選擇的緩存頭來控制緩存策略。
持久連接
HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理,在一個TCP連接上可以傳送多個HTTP請求和響應(yīng),減少了建立和關(guān)閉連接的消耗和延遲,在HTTP1.1中默認(rèn)開啟Connection: keep-alive,一定程度上彌補(bǔ)了HTTP1.0每次請求都要創(chuàng)建連接的缺點(diǎn)。
區(qū)別用一張圖來體現(xiàn):
增加Host頭部字段
在HTTP1.0中認(rèn)為每臺服務(wù)器都綁定一個唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機(jī)名(hostname)。但隨著虛擬主機(jī)技術(shù)的發(fā)展,在一臺物理服務(wù)器上可以存在多個虛擬主機(jī)(Multi-homed Web Servers),并且它們共享一個IP地址。HTTP1.1的請求消息和響應(yīng)消息都應(yīng)支持Host頭域,且請求消息中如果沒有Host頭域會報(bào)告一個錯誤(400 Bad Request)。
帶寬優(yōu)化及網(wǎng)絡(luò)連接的使用
HTTP1.0中,存在一些浪費(fèi)帶寬的現(xiàn)象,例如客戶端只是需要某個對象的一部分,而服務(wù)器卻將整個對象送過來了,并且不支持?jǐn)帱c(diǎn)續(xù)傳功能,HTTP1.1則在請求頭引入了range頭域,它允許只請求資源的某個部分,即返回碼是206(Partial Content),這樣就方便了開發(fā)者自由的選擇以便于充分利用帶寬和連接。
HTTP/2.0 特性
新的二進(jìn)制格式
HTTP1.x的解析是基于文本?;谖谋緟f(xié)議的格式解析存在天然缺陷,文本的表現(xiàn)形式有多樣性,要做到健壯性考慮的場景必然很多,二進(jìn)制則不同,只認(rèn)0和1的組合?;谶@種考慮HTTP2.0的協(xié)議解析決定采用二進(jìn)制格式,實(shí)現(xiàn)方便且健壯。
多路復(fù)用
即連接共享,即每一個request都是是用作連接共享機(jī)制的。一個request對應(yīng)一個id,這樣一個連接上可以有多個request,每個連接的request可以隨機(jī)的混雜在一起,接收方可以根據(jù)request的 id將request再歸屬到各自不同的服務(wù)端請求里面。
HTTP/2.0與HTTP/1.1區(qū)別

頭部壓縮
HTTP1.x的header帶有大量信息,而且每次都要重復(fù)發(fā)送,HTTP2.0使用encoder來減少需要傳輸?shù)膆eader大小,通訊雙方各自cache一份header fields表,既避免了重復(fù)header的傳輸,又減小了需要傳輸?shù)拇笮 ?/p>
服務(wù)端推送
HTTP/2.0之前版本,服務(wù)端總是被動的,客戶端主動請求才能返回?cái)?shù)據(jù)。2.0協(xié)議,服務(wù)端可以主動向客戶端發(fā)送數(shù)據(jù),例如:網(wǎng)頁有一個sytle.css的請求,在客戶端收到sytle.css數(shù)據(jù)的同時,服務(wù)端會將sytle.js的文件推送給客戶端,當(dāng)客戶端再次嘗試獲取sytle.js時就可以直接從緩存中獲取到,不用再發(fā)請求了。
