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

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

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

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

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

- 實(shí)現(xiàn)了快速握手功能
由于 QUIC 是基于 UDP 的,所以 QUIC 可以實(shí)現(xiàn)使用 0-RTT 或者 1-RTT 來建立連接,這意味著 QUIC 可以用最快的速度來發(fā)送和接收數(shù)據(jù),這樣可以大大提升首次打開頁面的速度。
記憶: 功加多握 (更(功)加(加)狠的多(多)我(握)的臉)
面對(duì)的問題
服務(wù)器和瀏覽器端都沒有對(duì) HTTP/3 提供比較完整的支持
系統(tǒng)內(nèi)核對(duì) UDP 的優(yōu)化遠(yuǎn)遠(yuǎn)沒有達(dá)到 TCP 的優(yōu)化程度,這也是阻礙 QUIC 的一個(gè)重要原因。
中間設(shè)備僵化的問題。這些設(shè)備對(duì) UDP 的優(yōu)化程度遠(yuǎn)遠(yuǎn)低于 TCP,據(jù)統(tǒng)計(jì)使用 QUIC 協(xié)議時(shí),大約有 3%~7% 的丟包率。
未來
從標(biāo)準(zhǔn)制定到實(shí)踐再到協(xié)議優(yōu)化還需要走很長(zhǎng)一段路;并且因?yàn)閯?dòng)了底層協(xié)議,所以 HTTP/3 的增長(zhǎng)會(huì)比較緩慢,這和 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