您當前的位置:首頁 > 詩詞

從HTTP0.9到HTTP2:一文讀懂HTTP協議的歷史演變和設計思路

作者:由 Jack Jiang 發表于 詩詞時間:2018-06-27

本文原作者阮一峰,作者部落格:

http://

ruanyifeng。com

1、引言

HTTP 協議是最重要的網際網路基礎協議之一,它從最初的僅為瀏覽網頁的目的進化到現在,已經是短連線通訊的事實工業標準,最新版本 HTTP/2 更是讓它再次成為技術熱點。

作為即時通訊開發者來說,深刻理解HTTP協議有助於在現今複雜行動網路環境下的最佳化和最佳實踐的開展,本文將通俗易懂的地介紹 HTTP 協議的歷史演變和設計思路。

從HTTP0.9到HTTP2:一文讀懂HTTP協議的歷史演變和設計思路

學習交流:

- 即時通訊開發交流3群:185926912[推薦]

- 移動端IM開發入門文章:《新手入門一篇就夠:從零開發移動端IM》

(本文同步釋出於:

http://www。

52im。net/thread-1709-1-

1。html

2、相關文章

《網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議》

《現代移動端網路短連線的最佳化手段總結:請求速度、弱網適應、安全保障》

《IM開發基礎知識補課(四):正確理解HTTP短連線中的Cookie、Session和Token》

《IM開發基礎知識補課:正確理解前置HTTP SSO單點登陸介面的原理》

《從HTTP到MQTT:一個基於位置服務的APP資料通訊實踐概述》

《技術掃盲:新一代基於UDP的低延時網路傳輸層協議——QUIC詳解》

《讓網際網路更快:新一代QUIC協議在騰訊的技術實踐分享》

3、HTTP/0。9

HTTP 是基於 TCP/IP 協議的應用層協議(詳見《網路程式設計懶人入門(一):快速理解網路通訊協議(上篇)》、《網路程式設計懶人入門(二):快速理解網路通訊協議(下篇)》)。它不涉及資料包(packet)傳輸,主要規定了客戶端和伺服器之間的通訊格式,預設使用80埠。

最早版本是1991年釋出的0.9版。該版本極其簡單,只有一個命令GET:

GET /index。html

上面命令表示,TCP 連線(connection)建立後,客戶端向伺服器請求(request)網頁index。html。

協議規定,伺服器只能迴應HTML格式的字串,不能迴應別的格式:

Hello World

伺服器傳送完畢,就關閉TCP連線。

4、HTTP/1。0

4。1 簡介

1996年5月,HTTP/1。0 版本釋出,內容大大增加(詳見 RFC1945)。

首先,任何格式的內容都可以傳送。這使得網際網路不僅可以傳輸文字,還能傳輸影象、影片、二進位制檔案。這為網際網路的大發展奠定了基礎。

其次,除了GET命令,還引入了POST命令和HEAD命令,豐富了瀏覽器與伺服器的互動手段。

再次,HTTP請求和迴應的格式也變了。除了資料部分,每次通訊都必須包括頭資訊(HTTP header),用來描述一些元資料。

其他的新增功能還包括狀態碼(status code)、多字符集支援、多部分發送(multi-part type)、許可權(authorization)、快取(cache)、內容編碼(content encoding)等。

4。2 請求格式

下面是一個1.0版的HTTP請求的例子:

GET / HTTP/1。0

User-Agent: Mozilla/5。0 (Macintosh; Intel Mac OS X 10_10_5)

Accept: */*

可以看到,這個格式與0。9版有很大變化。

第一行是請求命令,必須在尾部新增協議版本(HTTP/1。0)。後面就是多行頭資訊,描述客戶端的情況。

4。3 響應格式(Response)

伺服器的迴應如下:

HTTP/1。0 200 OK

Content-Type: text/plain

Content-Length: 137582

Expires: Thu, 05 Dec 1997 16:00:00 GMT

Last-Modified: Wed, 5 August 1996 15:55:28 GMT

Server: Apache 0。84

Hello World

迴應的格式是“頭資訊 + 一個空行(\r\n) + 資料”。其中,第一行是“協議版本 + 狀態碼(status code) + 狀態描述”。(詳見《網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議》)

4。4 Content-Type 欄位

關於字元的編碼,1。0版規定,頭資訊必須是 ASCII 碼,後面的資料可以是任何格式。因此,伺服器迴應的時候,必須告訴客戶端,資料是什麼格式,這就是Content-Type欄位的作用。

下面是一些常見的Content-Type欄位的值:

text/plain

text/html

text/css

image/jpeg

image/png

image/svg+xml

audio/mp4

video/mp4

application/javascript

application/pdf

application/zip

application/atom+xml

這些資料型別總稱為MIME type,每個值包括一級型別和二級型別,之間用斜槓分隔。

除了預定義的型別,廠商也可以自定義型別,就像下面這樣:

application/vnd。debian。binary-package

上面的型別表明,傳送的是Debian系統的二進位制資料包。

MIME type還可以在尾部使用分號,新增引數:

Content-Type: text/html; charset=utf-8

上面的型別表明,傳送的是網頁,而且編碼是UTF-8。

客戶端請求的時候,可以使用Accept欄位宣告自己可以接受哪些資料格式:

Accept: */*

上面程式碼中,客戶端宣告自己可以接受任何格式的資料。

MIME type不僅用在HTTP協議,還可以用在其他地方,比如HTML網頁:

4。5 Content-Encoding 欄位

由於傳送的資料可以是任何格式,因此可以把資料壓縮後再發送。

Content-Encoding欄位說明資料的壓縮方法:

Content-Encoding: gzip

Content-Encoding: compress

Content-Encoding: deflate

客戶端在請求時,用Accept-Encoding欄位說明自己可以接受哪些壓縮方法:

Accept-Encoding: gzip, deflate

4。6 缺點

HTTP/1。0 版的主要缺點是,每個TCP連線只能傳送一個請求。傳送資料完畢,連線就關閉,如果還要請求其他資源,就必須再新建一個連線。

TCP連線的新建成本很高,因為需要客戶端和伺服器三次握手,並且開始時傳送速率較慢(slow start)。所以,HTTP 1。0版本的效能比較差。隨著網頁載入的外部資源越來越多,這個問題就愈發突出了。

為了解決這個問題,有些瀏覽器在請求時,用了一個非標準的Connection欄位:

Connection: keep-alive

這個欄位要求伺服器不要關閉TCP連線,以便其他請求複用。

伺服器同樣迴應這個欄位:

Connection: keep-alive

一個可以複用的TCP連線就建立了,直到客戶端或伺服器主動關閉連線。但是,這不是標準欄位,不同實現的行為可能不一致,因此不是根本的解決辦法。

5、HTTP/1。1

1997年1月,HTTP/1。1 版本釋出,只比 1。0 版本晚了半年。HTTP/1。1進一步完善了 HTTP 協議,一直用到了20年後的今天,直到現在還是最流行的版本。

5。1 持久連線

1。1 版的最大變化,就是引入了持久連線(persistent connection),即TCP連線預設不關閉,可以被多個請求複用,不用宣告Connection: keep-alive。

客戶端和伺服器發現對方一段時間沒有活動,就可以主動關閉連線。

不過,規範的做法是,客戶端在最後一個請求時,傳送Connection: close,明確要求伺服器關閉TCP連線:

Connection: close

目前,對於同一個域名,大多數瀏覽器允許同時建立6個持久連線。

5。2 管道機制

1。1 版還引入了管道機制(pipelining),即在同一個TCP連線裡面,客戶端可以同時傳送多個請求。這樣就進一步改進了HTTP協議的效率。

舉例來說,客戶端需要請求兩個資源。以前的做法是,在同一個TCP連線裡面,先發送A請求,然後等待伺服器做出迴應,收到後再發出B請求。管道機制則是允許瀏覽器同時發出A請求和B請求,但是伺服器還是按照順序,先回應A請求,完成後再回應B請求。

5。3 Content-Length 欄位

一個TCP連線現在可以傳送多個迴應,勢必就要有一種機制,區分資料包是屬於哪一個迴應的。

這就是Content-length欄位的作用,宣告本次迴應的資料長度:

Content-Length: 3495

上面程式碼告訴瀏覽器,本次迴應的長度是3495個位元組,後面的位元組就屬於下一個迴應了。

在1。0版中,Content-Length欄位不是必需的,因為瀏覽器發現伺服器關閉了TCP連線,就表明收到的資料包已經全了。

5。4 分塊傳輸編碼

使用Content-Length欄位的前提條件是,伺服器傳送迴應之前,必須知道迴應的資料長度。

對於一些很耗時的動態操作來說,這意味著,伺服器要等到所有操作完成,才能傳送資料,顯然這樣的效率不高。更好的處理方法是,產生一塊資料,就傳送一塊,採用“流模式”(stream)取代“快取模式”(buffer)。

因此,1。1版規定可以不使用Content-Length欄位,而使用“分塊傳輸編碼”(chunked transfer encoding)。

只要請求或迴應的頭資訊有Transfer-Encoding欄位,就表明迴應將由數量未定的資料塊組成:

Transfer-Encoding: chunked

每個非空的資料塊之前,會有一個16進位制的數值,表示這個塊的長度。最後是一個大小為0的塊,就表示本次迴應的資料傳送完了。

下面是一個例子:

HTTP/1。1 200 OK

Content-Type: text/plain

Transfer-Encoding: chunked

25

This is the data in the first chunk

1C

and this is the second one

3

con

8

sequence

0

5。5 其他功能

1。1版還新增了許多動詞方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。

另外,客戶端請求的頭資訊新增了Host欄位,用來指定伺服器的域名:

Host: http://example。com

有了Host欄位,就可以將請求發往同一臺伺服器上的不同網站,為虛擬主機的興起打下了基礎。

5。6 缺點

雖然1。1版允許複用TCP連線,但是同一個TCP連線裡面,所有的資料通訊是按次序進行的。伺服器只有處理完一個迴應,才會進行下一個迴應。要是前面的迴應特別慢,後面就會有許多請求排隊等著。這稱為“隊頭堵塞”(Head-of-line blocking)。

為了避免這個問題,只有兩種方法:一是減少請求數,二是同時多開持久連線。這導致了很多的網頁最佳化技巧,比如合併指令碼和樣式表、將圖片嵌入CSS程式碼、域名分片(domain sharding)等等。如果HTTP協議設計得更好一些,這些額外的工作是可以避免的。

有關HTTP/1。1的詳細技術介紹,詳見《網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議》。

6、SPDY 協議

2009年,谷歌公開了自行研發的 SPDY 協議,主要解決 HTTP/1。1 效率不高的問題。

這個協議在Chrome瀏覽器上證明可行以後,就被當作 HTTP/2 的基礎,主要特性都在 HTTP/2 之中得到繼承。

7、HTTP/2

從HTTP0.9到HTTP2:一文讀懂HTTP協議的歷史演變和設計思路

2015年,HTTP/2 釋出。它不叫 HTTP/2。0,是因為標準委員會不打算再發布子版本了,下一個新版本將是 HTTP/3。

7。1 二進位制協議

HTTP/1。1 版的頭資訊肯定是文字(ASCII編碼),資料體可以是文字,也可以是二進位制。HTTP/2 則是一個徹底的二進位制協議,頭資訊和資料體都是二進位制,並且統稱為“幀”(frame):頭資訊幀和資料幀。

二進位制協議的一個好處是,可以定義額外的幀。HTTP/2 定義了近十種幀,為將來的高階應用打好了基礎。如果使用文字實現這種功能,解析資料將會變得非常麻煩,二進位制解析則方便得多。

7。2 多工

HTTP/2 複用TCP連線,在一個連線裡,客戶端和瀏覽器都可以同時傳送多個請求或迴應,而且不用按照順序一一對應,這樣就避免了“隊頭堵塞”。

舉例來說,在一個TCP連線裡面,伺服器同時收到了A請求和B請求,於是先回應A請求,結果發現處理過程非常耗時,於是就傳送A請求已經處理好的部分, 接著迴應B請求,完成後,再發送A請求剩下的部分。

這樣雙向的、實時的通訊,就叫做多工(Multiplexing)。

7。3 資料流

因為 HTTP/2 的資料包是不按順序傳送的,同一個連線裡面連續的資料包,可能屬於不同的迴應。因此,必須要對資料包做標記,指出它屬於哪個迴應。

HTTP/2 將每個請求或迴應的所有資料包,稱為一個數據流(stream)。每個資料流都有一個獨一無二的編號。資料包傳送的時候,都必須標記資料流ID,用來區分它屬於哪個資料流。另外還規定,客戶端發出的資料流,ID一律為奇數,伺服器發出的,ID為偶數。

資料流傳送到一半的時候,客戶端和伺服器都可以傳送訊號(RST_STREAM幀),取消這個資料流。1。1版取消資料流的唯一方法,就是關閉TCP連線。這就是說,HTTP/2 可以取消某一次請求,同時保證TCP連線還開啟著,可以被其他請求使用。

客戶端還可以指定資料流的優先順序。優先順序越高,伺服器就會越早迴應。

7。4 頭資訊壓縮

HTTP 協議不帶有狀態,每次請求都必須附上所有資訊。所以,請求的很多欄位都是重複的,比如Cookie和User Agent,一模一樣的內容,每次請求都必須附帶,這會浪費很多頻寬,也影響速度。

HTTP/2 對這一點做了最佳化,引入了頭資訊壓縮機制(header compression)。一方面,頭資訊使用gzip或compress壓縮後再發送;另一方面,客戶端和伺服器同時維護一張頭資訊表,所有欄位都會存入這個表,生成一個索引號,以後就不傳送同樣欄位了,只發送索引號,這樣就提高速度了。

7。5 伺服器推送

HTTP/2 允許伺服器未經請求,主動向客戶端傳送資源,這叫做伺服器推送(server push)。

常見場景是客戶端請求一個網頁,這個網頁裡面包含很多靜態資源。正常情況下,客戶端必須收到網頁後,解析HTML原始碼,發現有靜態資源,再發出靜態資源請求。其實,伺服器可以預期到客戶端請求網頁後,很可能會再請求靜態資源,所以就主動把這些靜態資源隨著網頁一起發給客戶端了。

附錄:更多網路通訊基礎資料

《TCP/IP詳解 - 第11章·UDP:使用者資料報協議》

《TCP/IP詳解 - 第17章·TCP:傳輸控制協議》

《TCP/IP詳解 - 第18章·TCP連線的建立與終止》

《TCP/IP詳解 - 第21章·TCP的超時與重傳》

《技術往事:改變世界的TCP/IP協議(珍貴多圖、手機慎點)》

《通俗易懂-深入理解TCP協議(上):理論基礎》

《通俗易懂-深入理解TCP協議(下):RTT、滑動視窗、擁塞處理》

《理論經典:TCP協議的3次握手與4次揮手過程詳解》

《理論聯絡實際:Wireshark抓包分析TCP 3次握手、4次揮手過程》

《計算機網路通訊協議關係圖(中文珍藏版)》

《UDP中一個包的大小最大能多大?》

《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》

《P2P技術詳解(二):P2P中的NAT穿越(打洞)方案詳解》

《P2P技術詳解(三):P2P技術之STUN、TURN、ICE詳解》

《通俗易懂:快速理解P2P技術中的NAT穿透原理》

《高效能網路程式設計(一):單臺伺服器併發TCP連線數到底可以有多少》

《高效能網路程式設計(二):上一個10年,著名的C10K併發連線問題》

《高效能網路程式設計(三):下一個10年,是時候考慮C10M併發問題了》

《高效能網路程式設計(四):從C10K到C10M高效能網路應用的理論探索》

《不為人知的網路程式設計(一):淺析TCP協議中的疑難雜症(上篇)》

《不為人知的網路程式設計(二):淺析TCP協議中的疑難雜症(下篇)》

《不為人知的網路程式設計(三):關閉TCP連線時為什麼會TIME_WAIT、CLOSE_WAIT》

《不為人知的網路程式設計(四):深入研究分析TCP的異常關閉》

《不為人知的網路程式設計(五):UDP的連線性和負載均衡》

《不為人知的網路程式設計(六):深入地理解UDP協議並用好它》

《不為人知的網路程式設計(七):如何讓不可靠的UDP變的可靠?》

《網路程式設計懶人入門(一):快速理解網路通訊協議(上篇)》

《網路程式設計懶人入門(二):快速理解網路通訊協議(下篇)》

《網路程式設計懶人入門(三):快速理解TCP協議一篇就夠》

《網路程式設計懶人入門(四):快速理解TCP和UDP的差異》

《網路程式設計懶人入門(五):快速理解為什麼說UDP有時比TCP更有優勢》

《網路程式設計懶人入門(六):史上最通俗的集線器、交換機、路由器功能原理入門》

《網路程式設計懶人入門(七):深入淺出,全面理解HTTP協議》

《技術掃盲:新一代基於UDP的低延時網路傳輸層協議——QUIC詳解》

《讓網際網路更快:新一代QUIC協議在騰訊的技術實踐分享》

《現代移動端網路短連線的最佳化手段總結:請求速度、弱網適應、安全保障》

《聊聊iOS中網路程式設計長連線的那些事》

《移動端IM開發者必讀(一):通俗易懂,理解行動網路的“弱”和“慢”》

《移動端IM開發者必讀(二):史上最全移動弱網路最佳化方法總結》

《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》

《IPv6技術詳解:基本概念、應用現狀、技術實踐(下篇)》

《從HTTP/0。9到HTTP/2:一文讀懂HTTP協議的歷史演變和設計思路》

>> 更多同類文章 ……

(本文同步釋出於:

http://www。

52im。net/thread-1709-1-

1。html

標簽: http  TCP  請求  客戶端  伺服器