一個HTTP,真有這么難嗎?
HTTP 是瀏覽器中最重要且使用最多的協(xié)議,是瀏覽器和服務器之間的通信語言。隨著瀏覽器的發(fā)展,HTTP 為了能適應新的形式也在持續(xù)進化。已經(jīng)歷經(jīng)0.9,1.0,1.1,2.0等幾個階段, 以及未來的3.0。
開頭先講個小故事,看完你可能滿臉黑人問號,但是別著急,等你把文章全讀完再回頭品一品這個小故事
我有多幢房子需要還貸。(多狀緩代)
但是突然有人來要錢,我手持水管虛晃了幾個動作就被他按在地上打哭了。(持管虛動安哭)
然后我不服,跟他進行了慢競賽,結(jié)果我被他多了一耳光又退縮了 (慢競?cè)?(多優(yōu)推縮)
之后我和他對視到眼睛都僵了(隊延僵)
結(jié)果他更加狠的多我的臉 (功加多握)
HTTP 0.9
出現(xiàn)時間
1991年
出現(xiàn)原因
用來在網(wǎng)絡之間傳遞 HTML 超文本的內(nèi)容。
實現(xiàn)
采用了基于請求響應的模式,從客戶端發(fā)出請求,服務器返回數(shù)據(jù)。
流程
- 因為 HTTP 都是基于 TCP 協(xié)議的,所以客戶端先要根據(jù) IP 地址、端口和服務器建立 TCP 連接,而建立連接的過程就是 TCP 協(xié)議三次握手的過程。
- 建立好連接之后,會發(fā)送一個 GET 請求行的信息,如GET /index.html用來獲取 index.html。
- 服務器接收請求信息之后,讀取對應的 HTML 文件,并將數(shù)據(jù)以 ASCII 字符流返回給客戶端。
- HTML 文檔傳輸完成后,斷開連接。
圖示

特點
- 只有一個請求行,并沒有 HTTP 請求頭和請求體因為只需要一個請求行就可以完整表達客戶端的需求了。
- 服務器也沒有返回頭信息。這是因為服務器端并不需要告訴客戶端太多信息,只需要返回數(shù)據(jù)就可以了。
- 返回的文件內(nèi)容是以 ASCII 字符流來傳輸?shù)?/li>
HTTP 1.0
出現(xiàn)時間
1994年
出現(xiàn)原因
隨著瀏覽器的發(fā)展在瀏覽器中展示的不單是 HTML 文件了,還包括了 JavaScript、CSS、圖片、音頻、視頻等不同類型的文件。因此需要支持多種類型的文件下載
文件格式不僅僅局限于 ASCII 編碼,還有很多其他類型編碼的文件。
圖示:

新增特性:(多狀緩代)
對多文件提供良好的支持,支持多種不同類型的數(shù)據(jù)。HTTP/1.0 的方案是通過請求頭和響應頭來進行協(xié)商,在發(fā)起請求時候會通過 HTTP 請求頭告訴服務器它期待服務器返回什么類型的文件、采取什么形式的壓縮、提供什么語言的文件以及文件的具體編碼。
- accept: text/html // 返回類型
- accept-encoding: gzip, deflate, br // 壓縮方式
- accept-Charset: ISO-8859-1,utf-8 // 編碼格式
- accept-language: zh-CN,zh // 語言
引入狀態(tài)碼,有的請求服務器可能無法處理,或者處理出錯,這時候就需要告訴瀏覽器服務器最終處理該請求的情況,狀態(tài)碼是通過響應行的方式來通知瀏覽器的。
提供了 Cache 機制,用來緩存已經(jīng)下載過的數(shù)據(jù)以減輕服務器的壓力
加入了用戶代理的字段以統(tǒng)計客戶端的基礎信息,比如 Windows 和 macOS 的用戶數(shù)量分別是多少。
記憶:多狀緩代(你有多幢(狀)房子需要還(緩)貸(代))
HTTP 1.1
出現(xiàn)時間
1999年
出現(xiàn)原因
隨著技術(shù)的繼續(xù)發(fā)展,需求也在不斷迭代更新,很快 HTTP/1.0 也不能滿足需求了。
新增特性:
- 改進持久連接。
- 由于http1.0是短連接,所以HTTP/1.0 每進行一次 HTTP 通信,都需要經(jīng)歷建立 TCP 連接、傳輸 HTTP 數(shù)據(jù)和斷開 TCP 連接三個階段。這樣做會增加大量的開銷。為解決這個問題,HTTP/1.1 中增加了持久連接的方法,它的特點是在一個 TCP 連接上可以傳輸多個 HTTP 請求,只要瀏覽器或者服務器沒有明確斷開連接,那么該 TCP 連接會一直保持。持久連接在 HTTP/1.1 中是默認開啟的,如不想采用持久連接,可以在 HTTP 請求頭中加上Connection: close。
- 目前瀏覽器中對于同一個域名,默認允許同時建立 6 個 TCP 持久連接。(TODO: 在此添加對比圖)
- 使用 CDN 的實現(xiàn)域名分片機制
- 不成熟的 HTTP 管線化
HTTP/1.1 中的管線化是指將多個 HTTP 請求整批提交給服務器的技術(shù),雖然可以整批發(fā)送請求,不過服務器依然需要根據(jù)請求順序來回復瀏覽器的請求。由于持久連接雖然能減少 TCP 的建立和斷開次數(shù),但是它需要等待前面的請求返回之后,才能進行下一次請求。如果 TCP 通道中的某個請求因為某些原因沒有及時返回,那么就會阻塞后面的所有請求,這就是著名的隊頭阻塞的問題。HTTP/1.1 試圖用管線化解決隊頭阻塞問題。
- 提供虛擬主機的支持
在 HTTP/1.0 中,每個域名綁定了一個唯一的 IP 地址,因此一個服務器只能支持一個域名。但是隨著虛擬主機技術(shù)的發(fā)展,需要實現(xiàn)在一臺物理主機上綁定多個虛擬主機,每個虛擬主機都有自己的單獨的域名,這些單獨的域名都公用同一個 IP 地址。因此,HTTP/1.1 的請求頭中增加了 Host 字段,用來表示當前的域名地址,這樣服務器就可以根據(jù)不同的 Host 值做不同的處理。
- 對動態(tài)生成的內(nèi)容提供了完美支持
HTTP/1.0 時,需要在響應頭中設置完整的數(shù)據(jù)大小,如Content-Length: 901,這樣瀏覽器就可以根據(jù)設置的數(shù)據(jù)大小來接收數(shù)據(jù)。不過隨著服務器端的技術(shù)發(fā)展,很多頁面的內(nèi)容都是動態(tài)生成的,因此在傳輸數(shù)據(jù)之前并不知道最終的數(shù)據(jù)大小,這就導致了瀏覽器不知道何時會接收完所有的文件數(shù)據(jù)。
HTTP/1.1 通過引入 Chunk transfer 機制(分塊傳輸編碼機制)來解決這個問題,服務器會將數(shù)據(jù)分割成若干個任意大小的數(shù)據(jù)塊,每個數(shù)據(jù)塊發(fā)送時會附上上個數(shù)據(jù)塊的長度,最后使用一個零長度的塊作為發(fā)送數(shù)據(jù)完成的標志。這樣就提供了對動態(tài)內(nèi)容的支持。
- 客戶端 Cookie、安全機制
HTTP/1.1 還引入了客戶端 Cookie 機制和安全機制
記憶:持管虛動安哭,手持水管虛晃了幾個動作就被人安在地上打哭了
HTTP 2.0
出現(xiàn)時間
2015年,大多數(shù)主流瀏覽器也于當年年底支持該標準
出現(xiàn)原因
雖然HTTP/1.1 采取了很多優(yōu)化資源加載速度的策略,也取得了一定的效果,但是 HTTP/1.1對帶寬的利用率卻并不理想。主要是由于以下幾個原因
- TCP 的慢啟動
一旦一個 TCP 連接建立之后,就進入了發(fā)送數(shù)據(jù)狀態(tài),剛開始 TCP 協(xié)議會采用一個非常慢的速度去發(fā)送數(shù)據(jù),然后慢慢加快發(fā)送數(shù)據(jù)的速度,直到發(fā)送數(shù)據(jù)的速度達到一個理想狀態(tài),我們把這個過程稱為慢啟動。慢啟動是 TCP 為了減少網(wǎng)絡擁塞的一種策略,我們是沒有辦法改變的。因為頁面中常用的一些關(guān)鍵資源文件本來就不大,如 HTML 文件、CSS 文件和 JavaScript 文件,通常這些文件在 TCP 連接建立好之后就要發(fā)起請求的,但這個過程是慢啟動,所以耗費的時間比正常的時間要多很多,這樣就增加了首次渲染頁面的時長了。
同時開啟了多條 TCP 連接,那么這些連接會競爭固定的帶寬
系統(tǒng)同時建立了多條 TCP 連接,當帶寬充足時,每條連接發(fā)送或者接收速度會慢慢向上增加,而一旦帶寬不足時,這些 TCP 連接又會減慢發(fā)送或者接收的速度。這樣就會出現(xiàn)一個問題,因為有的 TCP 連接下載的是一些關(guān)鍵資源,如 CSS 文件、JavaScript 文件等,而有的 TCP 連接下載的是圖片、視頻等普通的資源文件,但是多條 TCP 連接之間又不能協(xié)商讓哪些關(guān)鍵資源優(yōu)先下載,這樣就有可能影響那些關(guān)鍵資源的下載速度了。
- HTTP/1.1 隊頭阻塞的問題
在 HTTP/1.1 中使用持久連接時,雖然能公用一個 TCP 管道,但在一個管道中同一時刻只能處理一個請求,在當前的請求沒有結(jié)束之前,其他的請求只能處于阻塞狀態(tài)。這意味著我們不能隨意在一個管道中發(fā)送請求和接收內(nèi)容。這是一個很嚴重的問題,因為阻塞請求的因素有很多,并且都是一些不確定性的因素,假如有的請求被阻塞了 5 秒,那么后續(xù)排隊的請求都要延遲等待 5 秒,在這個等待的過程中,帶寬、CPU 都被白白浪費了。并且隊頭阻塞使得數(shù)據(jù)不能并行請求,所以隊頭阻塞是很不利于瀏覽器優(yōu)化的。
- 記憶:慢競?cè)?慢跑競賽
實現(xiàn)思路
HTTP/2 的思路就是一個域名只使用一個 TCP 長連接來傳輸數(shù)據(jù),這樣整個頁面資源的下載過程只需要一次慢啟動,同時也避免了多個 TCP 連接競爭帶寬所帶來的問題。另外隊頭阻塞的問題,等待請求完成后才能去請求下一個資源,這種方式無疑是最慢的,所以 HTTP/2 需要實現(xiàn)資源的并行請求,也就是任何時候都可以將請求發(fā)送給服務器,而并不需要等待其他請求的完成,然后服務器也可以隨時返回處理好的請求資源給瀏覽器。即一個域名只使用一個 TCP 長連接和消除隊頭阻塞問題
圖示:

新增特性
- 多路復用,通過引入二進制分幀層,就實現(xiàn)了 HTTP 的多路復用技術(shù)。
- 首先,瀏覽器準備好請求數(shù)據(jù),包括了請求行、請求頭等信息,如果是 POST 方法,那么還要有請求體這些數(shù)據(jù)經(jīng)過二進制分幀層處理之后,會被轉(zhuǎn)換為一個個帶有請求 ID 編號的幀,通過協(xié)議棧將這些幀發(fā)送給服務器。服務器接收到所有幀之后,會將所有相同 ID 的幀合并為一條完整的請求信息。然后服務器處理該條請求,并將處理的響應行、響應頭和響應體分別發(fā)送至二進制分幀層。同樣,二進制分幀層會將這些響應數(shù)據(jù)轉(zhuǎn)換為一個個帶有請求 ID 編號的幀,經(jīng)過協(xié)議棧發(fā)送給瀏覽器。瀏覽器接收到響應幀之后,會根據(jù) ID 編號將幀的數(shù)據(jù)提交給對應的請求。
- 設置請求的優(yōu)先級
我們知道瀏覽器中有些數(shù)據(jù)是非常重要的,但是在發(fā)送請求時,重要的請求可能會晚于那些不怎么重要的請求,如果服務器按照請求的順序來回復數(shù)據(jù),那么這個重要的數(shù)據(jù)就有可能推遲很久才能送達瀏覽器。為了解決這個問題,HTTP/2 提供了請求優(yōu)先級,可以在發(fā)送請求時,標上該請求的優(yōu)先級,這樣服務器接收到請求之后,會優(yōu)先處理優(yōu)先級高的請求。
- 服務器推送
除了設置請求的優(yōu)先級外,HTTP/2 還可以直接將數(shù)據(jù)提前推送到瀏覽器。
- 頭部壓縮
HTTP/2 對請求頭和響應頭進行了壓縮,你可能覺得一個 HTTP 的頭文件沒有多大,壓不壓縮可能關(guān)系不大,但你這樣想一下,在瀏覽器發(fā)送請求的時候,基本上都是發(fā)送 HTTP 請求頭,很少有請求體的發(fā)送,通常情況下頁面也有 100 個左右的資源,如果將這 100 個請求頭的數(shù)據(jù)壓縮為原來的 20%,那么傳輸效率肯定能得到大幅提升。
記憶: 多優(yōu)推縮 多了一耳光之后又(優(yōu))退(推)縮(縮)了
HTTP 3.0
出現(xiàn)原因
- TCP層面依舊存在隊頭阻塞
在 TCP 傳輸過程中,由于單個數(shù)據(jù)包的丟失會造成的阻塞。隨著丟包率的增加,HTTP/2 的傳輸效率也會越來越差。有測試數(shù)據(jù)表明,當系統(tǒng)達到了 2% 的丟包率時,HTTP/1.1 的傳輸效率反而比 HTTP/2 表現(xiàn)得更好。
- TCP 建立連接的延時
TCP 的握手過程也是影響傳輸效率的。我們知道 HTTP/1 和 HTTP/2 都是使用 TCP 協(xié)議來傳輸?shù)?,而如果使?HTTPS 的話,還需要使用 TLS 協(xié)議進行安全傳輸,而使用 TLS 也需要一個握手過程,這樣就需要有兩個握手延遲過程??傊?,在傳輸數(shù)據(jù)之前,我們需要花掉 3~4 個 RTT,若服務器相隔較遠,那么 1 個 RTT 就可能需要 100 毫秒以上了,這種情況下整個握手過程需要 300~400 毫秒,這時用戶就能明顯地感受到“慢”了。
- TCP 協(xié)議僵化
中間設備的僵化:如果我們在客戶端升級了 TCP 協(xié)議,但是當新協(xié)議的數(shù)據(jù)包經(jīng)過這些中間設備時,它們可能不理解包的內(nèi)容,于是這些數(shù)據(jù)就會被丟棄掉。這就是中間設備僵化,它是阻礙 TCP 更新的一大障礙。
操作系統(tǒng)也是導致 TCP 協(xié)議僵化的另外一個原因, 因為 TCP 協(xié)議都是通過操作系統(tǒng)內(nèi)核來實現(xiàn)的,應用程序只能使用不能修改。通常操作系統(tǒng)的更新都滯后于軟件的更新,因此要想自由地更新內(nèi)核中的 TCP 協(xié)議也是非常困難的。
記憶:隊延僵 對視到眼睛都僵了
實現(xiàn)思路
HTTP/3 選擇了一個折衷的方法——UDP 協(xié)議,基于 UDP 實現(xiàn)了類似于 TCP 的多路數(shù)據(jù)流、傳輸可靠性等功能,我們把這套功能稱為 QUIC 協(xié)議。

HTTP/2 和 HTTP/3 協(xié)議棧
特性
- 實現(xiàn)了類似 TCP 的流量控制、傳輸可靠性的功能
雖然 UDP 不提供可靠性的傳輸,但 QUIC 在 UDP 的基礎之上增加了一層來保證數(shù)據(jù)可靠性傳輸。它提供了數(shù)據(jù)包重傳、擁塞控制以及其他一些 TCP 中存在的特性。
- 集成了 TLS 加密功能
目前 QUIC 使用的是 TLS1.3,相較于早期版本 TLS1.3 有更多的優(yōu)點,其中最重要的一點是減少了握手所花費的 RTT 個數(shù)。
- 實現(xiàn)了 HTTP/2 中的多路復用功能
和 TCP 不同,QUIC 實現(xiàn)了在同一物理連接上可以有多個獨立的邏輯數(shù)據(jù)流。實現(xiàn)了數(shù)據(jù)流的單獨傳輸,就解決了 TCP 中隊頭阻塞的問題。

- 實現(xiàn)了快速握手功能
由于 QUIC 是基于 UDP 的,所以 QUIC 可以實現(xiàn)使用 0-RTT 或者 1-RTT 來建立連接,這意味著 QUIC 可以用最快的速度來發(fā)送和接收數(shù)據(jù),這樣可以大大提升首次打開頁面的速度。
記憶: 功加多握 (更(功)加(加)狠的多(多)我(握)的臉)
面對的問題
服務器和瀏覽器端都沒有對 HTTP/3 提供比較完整的支持
系統(tǒng)內(nèi)核對 UDP 的優(yōu)化遠遠沒有達到 TCP 的優(yōu)化程度,這也是阻礙 QUIC 的一個重要原因。
中間設備僵化的問題。這些設備對 UDP 的優(yōu)化程度遠遠低于 TCP,據(jù)統(tǒng)計使用 QUIC 協(xié)議時,大約有 3%~7% 的丟包率。
未來
從標準制定到實踐再到協(xié)議優(yōu)化還需要走很長一段路;并且因為動了底層協(xié)議,所以 HTTP/3 的增長會比較緩慢,這和 HTTP/2 有著本質(zhì)的區(qū)別。但是騰訊等公司已經(jīng)嘗試在生產(chǎn)中落地http3的使用,例如QQ興趣部落。
2020年五月初,微軟宣布開源自己的內(nèi)部 QUIC 庫 -- MsQuic,將全面推薦 QUIC 協(xié)議替換 TCP/IP 協(xié)議。
所以總體來說http3未來可期
作者:一只菜鳥攻城獅啊
來源:https://www.cnblogs.com/suihang/p/13265136.html


























