[譯] HTTP簡史

jerryOnlyZRJ發表於2019-02-09

簡介

超文字傳輸協議(HTTP)是 Internet 上最普遍和廣泛採用的應用程式協議之一:它是客戶端和伺服器之間的通用語言,支援現代 Web。從簡單的單一關鍵字和文件路徑開始,它已不再是瀏覽器的專屬,而且適用於幾乎所有連線網際網路的軟體和硬體應用程式的協議。

在本章中,我們將簡要介紹 HTTP 協議的演變。對不同 HTTP 語義的完整討論超出了本書的範圍,但是理解 HTTP 的關鍵設計變更以及每個變更背後的動機將為我們討論 HTTP 效能提供必要的背景知識,特別是本文中提及的 HTTP/2 即將進行的許多改進。

HTTP 0.9:單線協議

Tim Berners-Lee 最初的 HTTP 提案在設計時考慮到了 簡單性,以幫助他支撐他的另一個新生想法:全球資訊網。該策略似乎有效:有抱負的協議設計者,請注意

1991 年,Berners-Lee 概述了新協議產生的動機並列出了幾個高階設計目標:檔案傳輸功能、請求索引搜尋超文字存檔的能力、格式協商以及將客戶端引用到另一個伺服器的能力。為了證明該理論的實際應用,他構建了一個簡單的原型,它實現了所提議功能的一小部分:

  • 客戶端請求是單個 ASCII 字串。
  • 客戶請求由回車(CRLF)終止。
  • 伺服器響應是 ASCII 字元流。
  • 伺服器響應是一種超文字標記語言(HTML)。
  • 文件傳輸完成後終止連線。

其實並沒有那麼複雜,這些規則啟用的是一個一些 Web 伺服器當前依然支援的、非常簡單的並且 Telnet 友好的協議:

$> telnet google.com 80

Connected to 74.125.xxx.xxx

GET /about/

(hypertext response)
(connection closed)
複製程式碼

請求由單行:GET 方法和所請求文件的路徑組成。響應是單個超文字文件 — 沒有頭部或任何其他後設資料,只有 HTML,它真的不能再簡單了。此外,由於先前的互動是預期協議的子集,因此它私下裡也被叫做 HTTP/0.9。其餘的,正如他們所說,是歷史。

從1991年這些不起眼的開始,HTTP 開始了自己的生命,並在未來幾年迅速發展。讓我們快速回顧一下 HTTP/0.9 的功能:

  • 客戶端 - 伺服器,請求 - 響應協議。
  • ASCII 協議,執行在 TCP / IP 連結之上。
  • 旨在傳輸超文字文件(HTML)。
  • 每次請求後,伺服器和客戶端之間的連線都將關閉。

小提示:現階段流行的 Web 伺服器,如 Apache 和 Nginx,仍然有一部分支援 HTTP/0.9 協議,因為它真的特別簡單!如果您感到好奇,請開啟 Telnet 會話並嘗試通過 HTTP/0.9 訪問 google.com 或您自己喜歡的網站,並檢查此早期協議的行為和限制。

HTTP/1.0: 協議的快速發展和資訊 RFC

1991年至1995年期間是 HTML 規範的快速發展的階段,瀏覽器誕生,面向消費者的公共網際網路基礎設施出現並快速增長。

完美風暴:20 世紀 90 年代初的網際網路熱潮

在 Tim Berner-Lee 最初的瀏覽器原型的基礎上,國家超級計算應用中心(NCSA)的一個團隊決定實現他們自己的版本。這標誌著,第一個流行的瀏覽器誕生了:NCSA Mosaic。1994 年 10 月,NCSA 團隊的一名程式設計師 Marc Andreessen 與 Jim Clark 合作建立了 Mosaic Communications。該公司後來改名為 Netscape(網景),並於 1994 年 12 月釋出了 Netscape Navigator 1.0。從那時開始,一切已經很明朗了,全球資訊網不僅僅是一個學術熱點,它必將引起 更多的 關注。

實際上,同年第一次全球資訊網會議在瑞士日內瓦舉辦,以幫助指導 HTML 的發展為目的的全球資訊網聯盟(W3C)也由此誕生。在同一時期,在 IETF 內部同期建立了 HTTP 工作組(HTTP-WG),專注於改進 HTTP 協議。直到今天,他們依舊是網際網路的重要團隊,繼續推動網際網路的進化。

最後,為了創造完美的風暴,CompuServe 、AOL 和 Prodigy 在1994-1995年開始向公眾提供撥號上網服務。憑藉這股網際網路浪潮,Netscape 在1995年8月9日以非常成功的 IPO 創造了歷史 — 網際網路熱潮已經到來,每個人都想要分得一瓢羹!

越來越多的公共網站上的使用案例表明大眾對於新興網路的功能需求在不斷增加,這很快暴露了 HTTP/0.9 的許多根本限制:我們需要的協議不僅可以提供超文字文件,還可以提供有關請求和響應的更豐富的後設資料、啟用內容協商等。對此,新興的 Web 開發人員社群的迴應方式是,通過“實現,部署,並看是否有人開始採用它”這一專門的過程,來製作大批實驗性質的 HTTP 伺服器和客戶端。

從這段快速的實驗期開始,一系列最佳的實踐和常見的模式開始出現,1996 年 5 月,HTTP 工作組(HTTP-WG)釋出了 RFC 1945,它記錄了許多 HTTP/1.0 不規範但卻“常見”的實現方法。請注意,這只是一個資訊 RFC:HTTP/1.0 ,因為我們知道它不是正式規範或 Internet 標準!

話雖如此,但 HTTP/1.0 請求例項看起來卻非常熟悉:

$> telnet website.org 80

Connected to xxx.xxx.xxx.xxx

GET /rfc/rfc1945.txt HTTP/1.0 1⃣️
User-Agent: CERN-LineMode/2.15 libwww/2.17b3
Accept: */*

HTTP/1.0 200 OK 2⃣️
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 01 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 1 May 1996 12:45:26 GMT
Server: Apache 0.84

(plain-text response)
(connection closed)
複製程式碼

1⃣️ 具有HTTP版本號的請求行,後接請求頭

2⃣️具有響應狀態碼,後接響應頭

前面的變化儘管不只是 HTTP/1.0 功能的詳盡列表,但它確實說明了一些關鍵的協議更改:

  • 請求可能包含多個換行符分隔的頭部欄位。
  • 響應物件以響應狀態行為字首。
  • 響應物件有自己的一組換行符分隔的頭部欄位。
  • 響應物件不限於超文字。
  • 每次請求後,伺服器和客戶端之間的連線都將關閉。

請求和響應頭都應保證是 ASCII 編碼,但響應物件本身可以是任何型別:HTML 檔案、純文字檔案、影象或任何其他內容型別。因此,HTTP 的“超文字傳輸​​”部分在新特性引入後不久就變得不那麼恰當了。實際上,HTTP已經迅速發展成為 超媒體 傳輸,但原始名稱仍然存在。

除了媒體型別協商之外,RFC 還記錄了許多其他常用功能:內容編碼,字符集支援,多部分型別,授權,快取,代理行為,日期格式等。

小提示:如今,Web 上的幾乎所有伺服器都可以並且仍將使用 HTTP/1.0。除此之外,到現在為止,你應該更為了解了吧!每個請求需要新的 TCP 連線會對 HTTP/1.0 造成嚴重的效能損失。參考:三次握手,以及慢啟動

HTTP/1.1:Internet 標準

將 HTTP 轉變為官方 IETF 網際網路標準的工作與圍繞 HTTP/1.0 的文件工作並行進行,併發生在大約四年的時間內:1995 年至 1999 年。事實上,第一個正式的 HTTP/1.1 標準定義於 RFC 2068,在 HTTP/1.0 釋出大約六個月後於 1997 年 1 月正式釋出。兩年半之後,即 1999 年 6 月,標準中包含了許多改進和更新,並作為 RFC 2616 釋出。

HTTP/1.1 標準解決了早期版本中發現的許多協議歧義,並引入了許多關鍵效能優化:keep-alive 連線,分塊編碼傳輸,位元組範圍請求,附加快取機制,傳輸編碼和管道式請求。

有了這些能力,我們現在可以檢查由任何現代 HTTP 瀏覽器和客戶端執行的典型 HTTP/1.1 會話:

$> telnet website.org 80
Connected to xxx.xxx.xxx.xxx

GET /index.html HTTP/1.1 1⃣️

Host: website.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4)... (snip)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: __qca=P0-800083390... (snip)

HTTP/1.1 200 OK 2⃣️

Server: nginx/1.0.11
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Via: HTTP/1.1 GWA
Date: Wed, 25 Jul 2012 20:23:35 GMT
Expires: Wed, 25 Jul 2012 20:23:35 GMT
Cache-Control: max-age=0, no-cache
Transfer-Encoding: chunked

100 3⃣️

<!doctype html>
(snip)

100
(snip)

0 4⃣️

GET /favicon.ico HTTP/1.1 5⃣️

Host: www.website.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4)... (snip)
Accept: */*
Referer: http://website.org/
Connection: close 6⃣️

Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: __qca=P0-800083390... (snip)

HTTP/1.1 200 OK 7⃣️

Server: nginx/1.0.11
Content-Type: image/x-icon
Content-Length: 3638
Connection: close
Last-Modified: Thu, 19 Jul 2012 17:51:44 GMT
Cache-Control: max-age=315360000
Accept-Ranges: bytes
Via: HTTP/1.1 GWA
Date: Sat, 21 Jul 2012 21:35:22 GMT
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Etag: W/PSA-GAu26oXbDi

(icon data)
(connection closed)
複製程式碼

1⃣️ 請求 HTML 檔案,包含編碼,字符集和 cookie 後設資料

2⃣️ 原始 HTML 請求的分塊響應

3⃣️ 塊中的八位位元組數表示為 ASCII 十六進位制數(256 位元組)

4⃣️ 分塊流響應結束

5⃣️ 請求在同一 TCP 連線上建立的圖示檔案

6⃣️ 通知伺服器不會重用連線

7⃣️ 圖示響應,然後關閉連線

哎呀,那裡有太多事情發生!第一個也是最明顯的區別是我們有兩個物件請求,一個用於HTML頁面,另一個用於影象,兩者都通過單個連線傳遞。這是連線 keep-alive 的實際應用,它允許我們重用現有的 TCP 連線,以便對同一主機發出多個請求,並提供更快的終端使用者體驗。參閱 TCP 的優化

要終止持久連線,請注意第二個客戶端請求 close 通過 Connection 請求頭向伺服器傳送顯式指令。類似地,一旦傳輸響應,伺服器就可以通知客戶端關閉當前 TCP 連線的意圖。從技術上講,任何一方都可以在沒有此類訊號的情況下終止 TCP 連線,但客戶端和伺服器應儘可能提供它以在雙方上實現更好的連線重用策略。

小提示:HTTP/1.1 下將 HTTP 協議的語法更改為預設情況使用連線 keep-alive。這意味著,除非另有說明(通過 Connection: close 頭部),否則伺服器應預設保持連線處於開啟狀態。

但是,同樣的功能也被反向移植到 HTTP/1.0 並通過 Connection: Keep-Alive 頭部啟用。因此,如果您使用 HTTP/1.1,從技術上講,您不需要 Connection: Keep-Alive 請求頭,但許多客戶端仍然選擇提供它。

此外,HTTP/1.1 協議新增了內容,編碼,字符集,甚至語言協商,傳輸編碼,快取指令,客戶端 cookie,以及可以在每個請求上協商的十幾種其他功能。

我們不打算詳述每個 HTTP/1.1 功能的語義,因為它完全足夠寫成一本專業的書了,而且事實上也已經有很多類似的優秀書籍了。相反,前面的示例可以很好地說明 HTTP 的快速進展和演變,以及每個客戶端到伺服器之間交換的錯綜複雜。那裡有很多事情發生!

小提示:有關HTTP協議所有內部工作原理的詳細參考,請檢視 David Gourley 和 Brian Totty 撰寫的 O'Reilly 出版的 HTTP:The Definitive Guide

HTTP/2: 提高運輸效能

自發布以來,RFC 2616 已經成為網際網路空前增長的基礎:數十億臺各種形狀和大小的裝置,從臺式電腦到我們口袋裡的小型網路裝置,以及我們生活中都已離不開的每天都會用 HTTP 來傳送新聞、視訊以及數以百萬計的其他網路應用程式。

最初用於檢索超文字的簡單單行協議最終演變為通用的超媒體傳輸,或許十年之後甚至可用於為您能想象的任何需求提供支援。無處不在的伺服器以及協議在客戶端中的廣泛可用性,意味著現在許多應用程式都是專門在 HTTP 之上設計和部署的。

需要一個協議來控制你的咖啡壺?RFC 2324 已經涵蓋了超文字咖啡壺控制協議(HTCPCP/1.0)—— 原本是 IETF 的愚人節玩笑,卻漸漸的在我們新的超連線世界中不再是“玩笑”。

超文字傳輸協議(HTTP)是用於分散式協作超媒體資訊系統的應用程式級協議。它是一種通用的無狀態協議,可以通過擴充套件其請求方法,錯誤程式碼和頭部,用於擴充其用於超文字之外的許多工,例如名稱伺服器和分散式物件管理系統。HTTP 的一個特性是資料表示的輸入和協商,允許系統獨立於正在傳輸的資料而構建。

RFC 2616:HTTP/1.1,1999 年 6 月

HTTP 協議的簡捷性使其最初被廣泛採用和快速發展成為可能。事實上,現在發現使用 HTTP 作為主要控制和資料協議的嵌入式裝置(感測器,執行器和咖啡壺)並不罕見。但在其自身成功的重壓下,隨著我們越來越多地繼續將我們的日常互動轉移到網路 —— 社交、電子郵件、新聞、視訊以及越來越多的個人和工作空間 —— 它也開始顯示出有心無力的跡象。使用者和 Web 開發人員現在都要求 HTTP/1.1 提供近乎實時的響應和協議效能,如果不做出修改,它就無法滿足需求。

為了應對這些新挑戰,HTTP 必須繼續發展,因此 HTTPbis 工作組在2012年初宣佈了一項針對 HTTP/2 的新計劃:

新的實現專注於在保留 HTTP 的語義的基礎上,摒棄 HTTP/1.x 訊息框架和語法的遺留問題,這些問題已被確定為妨礙效能,而且極易造成底層傳輸的誤用。

工作組將基於 HTTP 當前的語義以及有序的全雙工模式中設計新的規範。與 HTTP/1.x 一樣,主要目標傳輸是 TCP,但應該可以使用其他傳輸。

HTTP/2 章程,2012 年 1 月

HTTP/2 的主要關注點是提高傳輸效能並實現更低的延遲和更高的吞吐量。主要的版本增幅聽起來是一個很大的步驟,就效能而言,它將是一個重要的步驟,但重要的是要注意,沒有任何高階協議語義受到影響:所有 HTTP 頭,值和使用者場景都是相同的。

任何現有的網站或應用程式都可以並且將通過 HTTP/2 傳送而無需做出任何修改:您無需變更您的應用程式以利用 HTTP/2。HTTP 伺服器將普遍使用 HTTP/2,但這應該成為大多數使用者的透明升級。如果工作組實現其目標,唯一的區別應該是我們的應用程式以更低的延遲和更好的網路連結利用率交付!

話雖如此,讓我們不要過於超前。在我們開始使用新的 HTTP/2 協議功能之前,值得退一步並檢查我們現有的 HTTP/1.1 部署和效能最佳實踐。HTTP/2 工作組正在新規範上取得快速進展,但即使最終標準已經完成並準備就緒,我們仍然必須在可預見的未來支援舊的 HTTP/1.1 客戶端。實際上,有可能會是十年或更長時間。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄