身為一個前端,HTTP 對我而言就像是云霧環(huán)繞的一座山,看不透也不知從哪開始攀登。深入學(xué)習(xí) HTTP 協(xié)議系列就是我對羅劍鋒老師的《透視 HTTP 協(xié)議》所做的總結(jié)。希望能對大家的登山之旅有所幫助。
當(dāng)我們在瀏覽器地址欄輸入網(wǎng)址再按下回車發(fā)生了什么?
- 瀏覽器發(fā)起域名解析獲取地址對應(yīng)的 IP;
- 瀏覽器用 TCP 的三次握手與服務(wù)器建立連接;
- 瀏覽器向服務(wù)器發(fā)送拼好的報文;
- 服務(wù)器收到報文后處理請求,同樣拼好報文再發(fā)給瀏覽器;
- 瀏覽器解析報文,渲染輸出頁面。
域名解析的過程中有多級緩存,瀏覽器先查看自身緩存,沒有再向操作系統(tǒng)緩存要,還沒有就檢查本機域名解析文件 hosts,最后則會用 DNS 域名解析系統(tǒng)進行。在這個過程中可能會經(jīng)歷 CDN 解析,拿到 CDN 服務(wù)器的地址
在達到目標(biāo)服務(wù)器后,通常會經(jīng)歷負載均衡設(shè)備,負載均衡設(shè)備會訪問系統(tǒng)里的緩存服務(wù)器,通常有 memory 級緩存 Redis 和 disk 級緩存 Varnish。
如果緩存服務(wù)器里沒有所要數(shù)據(jù),就會把請求轉(zhuǎn)發(fā)給應(yīng)用服務(wù)器,例如 Java 的 Tomcat/Netty/Jetty,Python 的 Django,還有 PHP、Node.js、Golang 等等。然應(yīng)用服務(wù)器處理完成后把執(zhí)行的結(jié)果返回給負載均衡設(shè)備。
到達負載均衡后請求的處理就完成了,會按照請求順序原路返回。
HTTP 協(xié)議的核心部分 - HTTP 報文
報文結(jié)構(gòu)
HTTP 協(xié)議的請求報文和響應(yīng)報文的結(jié)構(gòu)由三大部分組成
- 起始行(start line):描述請求或相應(yīng)的基本信息;
- 頭部字段集合(header):key-value 的形式;
- 消息正文(entity):實際傳輸數(shù)據(jù)。
其中前兩部分經(jīng)常被稱為 請求頭/響應(yīng)頭,正文部分稱為body。
HTTP 協(xié)議規(guī)定報文必須有 header,可以沒有 body,在 header 和 body 之間必須有一個空行,如下圖所示。

抓包分析

圖中 1,第一行為請求行部分。2,為 header 部分,3 是空白行部分。這里沒有發(fā)送 body,所以沒有 body 信息。
請求行
報文的起始行就是請求行,它簡要的描述了客戶端想要如何操作服務(wù)器端的資源。
GET / HTTP / 1.1;
在抓包獲取的信息中,我們可以看到請求頭由三部分組成:
- 請求方法,表示對資源的操作,對應(yīng)上面代碼中的 GET,;
- 請求目標(biāo),通常是一個 URI,表記錄請求方法要操作的資源,對應(yīng)
/; - 版本號:表示報文使用的 HTTP 協(xié)議版本,對應(yīng)
HTTP/1.1。
這三個部分通常用空格來分隔,最后用 CRLF 換行表示結(jié)束,用圖片來描述就是下面這個方式。

狀態(tài)行
服務(wù)器響應(yīng)報文里的起始行叫做狀態(tài)行,表示服務(wù)器響應(yīng)的狀態(tài)。
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
也由三部分組成:
- 版本號,表示報文使用的 HTTP 協(xié)議版本號;
- 狀態(tài)碼,表示處理結(jié)果,如 200 成功,500 服務(wù)器錯誤;
- 原因:作為數(shù)字狀態(tài)碼的補充,在上面代碼是
OK。
它的組成規(guī)則和請求行一致,用空格來分隔,用 CRLF 換行表示結(jié)束,如下圖所示。

頭部字段(header)
請求行/狀態(tài)行加上頭部字段(header),就組成了請求頭/響應(yīng)頭。
如下圖所示:

頭部字段是 key-value 的形式,之間用 : 分隔,最后用 CRLF 換行表示結(jié)束。
注意:
- 字段不區(qū)分大小寫,不允許出現(xiàn)下劃線
_,可以使用短橫線-連接。 - key 后面緊跟
:,不能有空格。但是:和 value 之間可以出現(xiàn)空格。 - 字段的順序是無意義的。
- 字段原則上不能出現(xiàn)重復(fù),除非字段本身語義允許,如 Set-Cookie。
- 在請求頭/響應(yīng)頭中只有
Host字段是必須的。
HTTP 請求方法
標(biāo)準(zhǔn)請求方法
- GET:獲取資源,可以理解為讀取或者下載數(shù)據(jù);
- HEAD:獲取資源的元信息;POST:向資源提交數(shù)據(jù),相當(dāng)于寫入或上傳數(shù)據(jù);
- PUT:類似 POST;DELETE:刪除資源;
- CONNECT:建立特殊的連接隧道;
- OPTIONS:列出可對資源實行的方法;
- TRACE:追蹤請求 - 響應(yīng)的傳輸路徑。

常用方法
GET 和 HEAD
GET 的含義是從服務(wù)器獲取資源,可以搭配 URI 和其他頭部字段實現(xiàn)對資源更精細的操作。
HEAD 的含義與 GET 類似,都是從服務(wù)器獲取資源,服務(wù)器處理機制也一樣,但服務(wù)器不會返回請求的實體數(shù)據(jù),只會傳回響應(yīng)頭,也就是資源的“元信息”。可以將他看做 GET 的簡化版。
POST 和 PUT
POST 和 PUT 是指向 URI 指定資源提交數(shù)據(jù),而 POST 和 PUT 的區(qū)別在于 POST 意味著“新建”,PUT 則是 “修改”。
其他方法
DELETE:指示服務(wù)器刪除資源。
CONNECT:要求服務(wù)器為客戶端和另一臺遠程服務(wù)器建立一條通道,瀏覽器充當(dāng)代理角色。
OPTIONS:要求服務(wù)器列出可對資源實行的請求方法。
TRACE:用于對 HTTP 鏈路的測試或診斷。
安全和冪等
安全在 HTTP 協(xié)議里是指請求方法不會修改服務(wù)器上的資源。所以只有 GET 和 HEAD 是安全的,因為它們對資源進行是只讀操作。
冪等意思是多次執(zhí)行相同操作,結(jié)果也都是相同的,即多次“冪”后“相等”。
可以看出 GET 和 HEAD 既是安全的也是冪等的,DELETE 是冪等的,POST 和 PUT 既不安全也不冪等。
URI 與 網(wǎng)址
URI:統(tǒng)一資源標(biāo)識符,包括 URL 和 URN 兩部分。
URL:統(tǒng)一資源定位符,就是我們俗稱的“網(wǎng)絡(luò)地址”,因為 URL 十分普遍,所以通常用 URL 表示 URL 或 URI。
URL 格式
URL 本質(zhì)上是一個字符串,它的作用是 唯一的標(biāo)記資源的位置或者名字。它不僅能標(biāo)記萬維網(wǎng)資源,還能標(biāo)記動態(tài)服務(wù)資源或者本地資源。
它的組成部分如下圖所示:由 scheme、host:port、path 和 query 組成。

URI 的第一個組成部分是 scheme 代表協(xié)議名,表示資源應(yīng)該用那種協(xié)議訪問(如:http、ftp、file)。
scheme 之后就是固定的三個字符“://”,用來把 scheme 和后面的部分分離開。
“://”之后是 authority 部分,表示資源所在的主機名,通常形式是 host:port ,即主機名加端口號。主機名必須要有,可以是 IP 地址或域名。端口號可以省略,瀏覽器等客戶端會根據(jù) scheme 使用默認的端口號,例如 HTTP 默認的是 80,HTTPS 默認的是 443。
path 是用來標(biāo)記資源所在位置。path 采用的是類似路徑的表示方式,URI 的 path 必須要以 “/” 開始。
看下面這個例子
https://tools.ietf.org/html/rfc7230
https 是 scheme,表示使用的是 https 協(xié)議,tools.ietf.org 就是主機名,這里默認訪問端口號是 443,路徑就是后面的 /html/rfc7230。
URI 的查詢參數(shù) query
在上圖 URL path 后還有一個 query 部分,query 由一個“?”開始,但不包含“?”,表示對資源附加的額外要求。
query 的格式是由 多個 “key=value” 組成,多個 “key=value” 之間用 “&” 連接。
URI 的編碼
URI 中只能使用 ASCII 碼,對于英語以外的漢語、日語及其他字符 URI 會對他們進行 encodeURI 轉(zhuǎn)義。
轉(zhuǎn)義規(guī)則是,把字符(unicode)編碼成 utf-8,utf-8 是用 1-4 個字節(jié)表示的,所以每個字節(jié)轉(zhuǎn)換成 16 進制并在前面用百分號(%)連接,最后并把每個字節(jié)轉(zhuǎn)換的結(jié)果連接起來。
響應(yīng)狀態(tài)碼
五類狀態(tài)碼
RFC 標(biāo)準(zhǔn)把狀態(tài)碼分成了以下五類
- 1××:提示信息,表示目前是協(xié)議處理的中間狀態(tài),還需要后續(xù)的操作;
- 2××:成功,報文已經(jīng)收到并被正確處理;
- 3××:重定向,資源位置發(fā)生變動,需要客戶端重新發(fā)送請求;
- 4××:客戶端錯誤,請求報文有誤,服務(wù)器無法處理;
- 5××:服務(wù)器錯誤,服務(wù)器在處理請求時內(nèi)部發(fā)生了錯誤。
常見響應(yīng)狀態(tài)碼及含義
- 1xx
- 101 Switching Protocols,客戶端要求服務(wù)端改成其他協(xié)議繼續(xù)通信,如果服務(wù)器統(tǒng)一變更協(xié)議,就會返回狀態(tài)碼 101.
- 2xx
- 200 OK,表示請求成功,通常在響應(yīng)頭后會有 body 數(shù)據(jù)。
- 204 No Content,也表示請求成功,它與 200 的區(qū)別在于,響應(yīng)頭后沒有 body 數(shù)據(jù)。
- 206 Partial Content,常見于獲取請求資源的部分數(shù)據(jù)。“Content-Range”,表示 body 里返回數(shù)據(jù)的具體范圍。
- 3xx
- 301 Moved Permanently,表示永久重定向。
- 302 Found,表示臨時重定向,瀏覽器不會對臨時重定向的內(nèi)容做緩存優(yōu)化。
- 304 Not Modified,緩存重定向,用戶緩存控制,URL 不包含跳轉(zhuǎn)含義。
- 4xx
- 400 Bad Request,表示請求錯誤。
- 403 Forbidden,表示服務(wù)器禁止訪問資源。
- 404 Not Found,表示資源在服務(wù)器上未找到。
- 5xx
- 500 Internal Server Error,表示服務(wù)器發(fā)生錯誤,是一個較通用的錯誤碼。
- 502 Bad Gateway,表示服務(wù)器禁止訪問資源。
- 503 Service Unavailable,表示服務(wù)器正忙,暫時無法響應(yīng)。
HTTP 的特點和優(yōu)缺點
五大特點
- HTTP 是靈活可擴展的,可以任意添加頭字段實現(xiàn)任意功能;
- HTTP 是可靠傳輸協(xié)議,基于 TCP/IP 協(xié)議“盡量”保證數(shù)據(jù)的送達;
- HTTP 是應(yīng)用層協(xié)議,比 FTP、SSH 等更通用功能更多,能夠傳輸任意數(shù)據(jù);
- HTTP 使用了請求 - 應(yīng)答模式,客戶端主動發(fā)起請求,服務(wù)器被動回復(fù)請求;
- HTTP 本質(zhì)上是無狀態(tài)的,每個請求都是互相獨立、毫無關(guān)聯(lián)的,協(xié)議不要求客戶端或服務(wù)器記錄請求相關(guān)的信息。
優(yōu)缺點
-
優(yōu)點:
- 靈活可拓展;
- 應(yīng)用廣泛,環(huán)境成熟;
- 無狀態(tài),不需要額外資源來記錄路狀態(tài)信息,減輕服務(wù)器負擔(dān);
- 明文傳輸,數(shù)據(jù)可直接查看到,方便開發(fā)調(diào)試。
-
缺點:
- 無狀態(tài),每次訪問都要獲取一遍身份信息;
- 明文傳輸,數(shù)據(jù)容易被截??;
- 不安全,數(shù)據(jù)在傳輸過程中容易被篡改。