- 原文地址:HTTP/2 Frequently Asked Questions
- 原文做者:HTTP/2
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:YueYong
- 校對者:Ranjay, ziyin feng
如下是有關 HTTP/2 的常見問題解答。php
HTTP/1.1 已經在 Web 上服役了十五年以上,但其劣勢也開始顯現。html
加載一個網頁比以往更加耗費資源(詳見 HTTP Archive’s page size statistics)。與此同時,有效地加載全部這些靜態資源變得很是困難,由於事實上,HTTP 只容許每一個 TCP 鏈接有一個未完成的請求。前端
在過去,瀏覽器使用多個 TCP 鏈接來發出並行請求。然而這種作法是有限制的。若是使用了太多的鏈接,就會產生相反的效果(TCP 擁塞控制將被無效化,致使的用塞事件將會損害性能和網絡)。並且從根本上講這對其餘程序來講也是不公平的(由於瀏覽器會佔用許多本不應屬於他的資源)。node
同時,大量的請求意味着「在線上」有大量重複的數據。android
這兩個因素都意味着 HTTP/1.1 請求有不少與之相關的開銷;若是請求太多,則會影響性能。ios
這使得業界在有哪些是最好的實踐上達成共識,它們包括,好比,Spriting(圖片合併)、data: inlining(數據內嵌)、Domain Sharding(域名分片)和 Concatenation(文件合併)等。這些不規範的解決方案說明了協議自己存在一些潛在問題,而且在使用的時候會出現不少問題。nginx
HTTP/2 是由 IETF 的 HTTP 工做組開發的,該組織負責維護 HTTP 協議。該組織由衆多 HTTP 實現者、用戶、網絡運營商和 HTTP 專家組成。git
值得注意的是,雖然工做組的郵件列表託管在 W3C 網站上,不過這並非 W3C 的功勞。可是, Tim Berners-Lee 和 W3C TAG與 WG 的進度保持一致。github
許多人爲這項工做作出了本身的貢獻,尤爲是一些來自「大」項目的工程師,例如 Firefox、Chrome、Twitter、Microsoft 的 HTTP stack、Curl 和 Akamai。以及若干 Python、Ruby 和 NodeJS 的 HTTP 實現者。算法
爲了更好的瞭解有關 IETF 的信息,你能夠訪問 Tao of the IETF;你也能夠在 Github 的貢獻者圖表上查看有哪些人爲該項目作出了貢獻,一樣的,你也能夠在 implementation list 上查看誰正在參與該項目。
HTTP/2 第一次出現並被討論的時候,SPDY 正獲得廠商 (像 Mozilla 和 nginx)的青睞和支持,並被當作是 HTTP/1.x 基礎上的重大改善。
在不斷的徵求建議以及投票選擇以後,SPDY/2 被選爲 HTTP/2 的基礎。從那時起,根據工做組的討論和用戶的反饋,它已經有了不少變化。
在整個過程當中,SPDY 的核心開發人員參與了 HTTP/2 的開發,其中包括 Mike Belshe 和 Roberto Peon。
2015 年 2 月,谷歌宣佈計劃取消對 SPDY 的支持,轉而支持 HTTP/2。
工做組決定刪除次要版本(「.0」),由於它在 HTTP/1.x 中形成了不少混亂。也就是說,HTTP 的版本僅表明它的兼容性,不表示它的特性和「亮點」。
在高版本 HTTP/2 中:
和 HTTP/1.x 這樣的文本協議相比,二進制協議解析起來更高效、「線上」更緊湊,更重要的是錯誤更少。由於它們對如空白字符的處理、大小寫、行尾、空連接等的處理頗有幫助。
舉個栗子 🌰,HTTP/1.1 定義了四種不一樣的方法來解析一條消息;而在HTTP/2中,僅需一個代碼路徑便可。
HTTP/2 在 telnet 中不可用,可是咱們已經有一些工具能夠提供支持,例如 Wireshark plugin。
HTTP/1.x 有個問題叫「隊頭阻塞(head-of-line blocking)」,它是指在一次鏈接(connection)中,只提交一個請求的效率比較高,多了就會變慢。
HTTP/1.1 嘗試使用管線化(pipelining)來解決這個問題,可是效果並不理想(對於數據量較大或者速度較慢的響應,依舊會阻礙排在他後面的請求)。此外,因爲許多網絡媒介(intermediary)和服務器不能很好的支持管線化,致使其部署起來也是困難重重。
這也就迫使客戶端使用一些啓發式的方法(基本靠猜)來決定經過哪些鏈接提交哪些請求;因爲一個頁面加載的數據量,每每比可用鏈接能處理的數據量的 10 倍還多,對性能產生極大的負面影響,結果常常引發瀑布式阻塞(waterfall of blocked requests)。
而多路傳輸(Multiplexing)能很好的解決這些問題,由於它能同時處理多個消息的請求和響應;甚至能夠在傳輸過程當中將一個消息跟另一個摻雜在一塊兒。
因此在這種狀況下,客戶端只須要一個鏈接就能加載一個頁面。
若是使用 HTTP/1,瀏覽器打開每一個點(origin)就須要 4 到 8 個鏈接(Connection)。而如今不少網站都使用多點傳輸(multiple origins),也就是說,光加載一個網頁,打開的鏈接數量就超過 30 個。
一個應用同時打開這麼多鏈接,已經遠遠超出了當初設計 TCP 時的預想;同時,由於每一個鏈接都會響應大量的數據,使其能夠形成網絡緩存溢出的風險,結果可能致使網絡堵塞和數據重傳。
此外,使用這麼多鏈接還會強佔許多網絡資源。這些資源都是從那些「遵紀守法」的應用那「偷」的(VoIP 就是個很好的例子)。
當瀏覽器請求頁面時,服務器發送 HTML 做爲響應,而後須要等待瀏覽器解析 HTML 併發出對全部嵌入資源的請求,而後才能開始發送 JavaScript,圖像和 CSS。
服務器推送服務經過「推送」那些它認爲客戶端將會須要的內容到客戶端的緩存中,以此來避免往返的延遲。
可是,推送的響應並非「萬金油」,若是使用不當,可能會損害性能。正確使用服務器推送是一個長期的實驗及研究領域。
來自 Mozilla 的 Patrick McManus 經過計算消息頭對平均頁面負載的印象,對此進行了形象且充分的說明。
假定一個頁面有 80 個資源須要加載(這個數量對於今天的 Web 而言仍是挺保守的),而每一次請求都有 1400 字節的消息頭(這一樣也並很多見,由於 Cookie 和引用等東西的存在),至少要 7 到 8 個來回去「在線」得到這些消息頭。這還不包括響應時間——那只是從客戶端那裏獲取到它們所花的時間而已。
這全都因爲 TCP 的慢啓動機制,它根據能夠確認的數據包數量對新鏈接上發送數據的進行限制 — 這有效地限制了最初的幾回來回能夠發送的數據包數量。
相比之下,即便是頭部輕微的壓縮也能夠是讓那些請求只需一個來回就能搞定——有時候甚至一個包就能夠了。
這些額外的開銷是至關多的,特別是當你考慮對移動客戶端的影響的時候。這些往返的延遲,即便在網絡情況良好的狀況下,也高達數百毫秒。
SPDY/2 提出在每一方都使用一個單獨的 GZIP 上下文用於消息頭壓縮,這實現起來很容易,也很高效。
從那時起,一個重要的攻擊方式 CRIME 誕生了,這種方式能夠攻擊加密文件內部的所使用的壓縮流(如GZIP)。
使用 CRIME,那些具有向加密數據流中注入數據能力的攻擊者得到了「探測」明文並還原的可能性。由於是 Web,JavaScript 使其成爲了可能,並且已經有了經過對受到 TLS 保護的 HTTP 資源的使用CRIME來還原出 cookies 和認證令牌(Toekn)的案例。
所以,咱們不該該使用 GZIP 進行壓縮。因爲找不到其它適合在這種用例下使用的安全有效的算法,因此咱們創造了一種新的,針對消息頭的,進行粗粒度操做的壓縮模式;由於HTTP消息頭並不經常須要改變,咱們仍然能夠獲得很好的壓縮效率,並且更加的安全。
這一努力被許可在網絡協議的一個修訂版本上運行 – 例如,HTTP 消息頭、方法等等如何才能在不改變 HTTP 語義的前提下放到「網絡上」。
這是由於 HTTP 的應用很是普遍。若是咱們使用了這個版本的 HTTP,它就會引入一種新的狀態機制(例如以前討論過的例子)或者改變其核心方法(幸虧,這尚未發生過),這可能就意味着新的協議將不會兼容現有的 Web 內容。
具體地,咱們是想要可以從 HTTP/1 轉移到 HTTP/2,而且不會有信息的丟失。若是咱們開始」清理」消息頭(大多數人都認爲如今的 HTTP 消息頭簡直是一團糟),咱們就不得不去面對現有 Web 的諸多問題。
這樣作只會對新協議的普及形成麻煩。
總而言之,工做組 會對全部的 HTTP 負責,而不只僅只是 HTTP/2。所以,咱們才能夠在版本獨立的新機制下運做,只要它們也能同現有的網絡向下兼容。
若是非瀏覽器應用已經使用過 HTTP 的話,那他們也應該可使用 HTTP/2。
先前收到過 HTTP 「APIs」 在 HTTP/2 中具備良好性能等特色這樣的反饋,那是由於 API 的設計不須要考慮相似請求開銷這樣一些事情。
話雖如此,咱們正在考慮的改進重點是典型的瀏覽用例,由於這是協議主要的使用場景。
咱們的章程裏面是這樣說的:
正在組織的規範須要知足如今已經廣泛部署了的 HTTP 的功能要求;具體來講主要包括,Web 瀏覽(桌面端和移動端),非瀏覽器(「HTTP APIs」 形式的),Web 服務(大範圍的),還有各類網絡中介(藉助代理,企業防火牆,反向代理以及內容分發網絡實現的)。一樣的,對 HTTP/1.x 當前和將來的語義擴展 (例如,消息頭,方法,狀態碼,緩存指令) 都應該在新的協議中支持。
值得注意的是,這裏沒有包括將 HTTP 用於非特定行爲所依賴的場景中(例如超時,鏈接狀態以及攔截代理)。這些可能並不會被最終的產品啓用。
不須要。在激烈的討論後,工做組沒有就新協議是否使用加密(如 TLS)而達成共識。
不過,有些觀點認爲只有在加密鏈接上使用時纔會支持 HTTP/2,而目前尚未瀏覽器支持未加密的 HTTP/2。
HTTP/2 定義了所需的 TLS 文檔,包括版本,密碼套件黑名單和使用的擴展。
細節詳見相關規範。
還有對於一些額外機制的討論,例如對 HTTP:// URLs(所謂的「機會主義加密」)使用 TLS;詳見 RFC 8164。
瀏覽器中,最新版本的 Edge、Safari、Firefox 和 Chrome都支持 HTTP/2。其餘基於 Blink 的瀏覽器也將支持HTTP/2(例如 Opera 和 Yandex 瀏覽器)。詳見 caniuse。
還有幾個可用的服務器(包括來自 Akamai,Google 和 Twitter 的主要站點的 beta 支持),以及許多能夠部署和測試的開源實現。
有關詳細信息,請參閱實現列表。
工做組的目的是讓那些使用 HTTP/1.x 的人也可使用 HTTP/2,並能得到 HTTP/2 所帶來的好處。他們說過,因爲人們部署代理和服務器的方式不一樣,咱們不能強迫整個世界進行遷移,因此 HTTP/1.x 仍有可能要使用了一段時間。
若是經過 HTTP/2 引入的溝通協做機制運行良好,支持新版本的 HTTP 就會比過去更加容易。
數據接續的存在是因爲一個值(例如 cookie)能夠超過 16kb,這意味着它不可能所有裝進一個幀裏面。
因此就決定以最不容易出錯的方式讓全部的消息頭數據以一個接一個幀的方式傳遞,這樣就使得對消息頭的解碼和緩衝區的管理變得更加容易。
接收一方老是會控制 HPACK 中內存的使用量, 而且最小能設置到 0,最大則要看 SETTING 幀中能表示的最大整型數是多少,目前是 2^32 - 1。
發送一個 SETTINGS 幀,將狀態尺寸(SETTINGS_HEADER_TABLE_SIZE)設置到 0,而後 RST 全部的流,直到一個帶有 ACT 設置位的 SETTINGS 幀被接收。
簡單說一下。
原來的提案裏面提到了流分組這個概念,它能夠共享上下文,進行流控制等等。儘管那樣有利於代理(也有利於用戶體驗),可是這樣作相應也會增長一點複雜度。因此咱們就決定先以一個簡單的東西開始,看看它會有多糟糕的問題,而且在將來的協議版本中解決這些問題(若是有的話)。
因爲 CPU 效率和安全的緣由,HPACK 的霍夫曼編碼填充了霍夫曼編碼字符串的下一個字節邊界。所以對於任何特定的字符串可能須要 0-7 個比特的填充。
若是單獨考慮霍夫曼解碼,任何比所須要的填充長的符號均可以正常工做。可是,HPACK 的設計容許按字節對比霍夫曼編碼的字符串。經過填充 EOS 符號須要的比特,咱們確保用戶在作霍夫曼編碼字符串字節級比較時是相等的。反之,許多 headers 能夠在不須要霍夫曼解碼的狀況下被解析。
一般/大部分時候能夠。
對於運行在 TLS(h2
)之上的 HTTP/2 而言,若是你沒有實現 http1.1
的 ALPN 標識,那你就不須要支持任何 HTTP/1.1 的特性。
對於運行在 TCP(h2c
)之上的 HTTP/2 而言,你須要實現最初始的升級(Upgrade)請求。
只支持 h2c
的客戶端須要生成一個針對 OPTIONS 的請求,由於 「*」
或者一個針對 「/」 的 HEAD 請求,他們至關安全,而且也很容易構建。僅僅只但願實現 HTTP/2 的客戶端應當把沒有帶上 101 狀態碼的 HTTP/1.1 響應看作錯誤處理。
只支持 h2c
的服務器可使用一個固定的 101 響應來接收一個包含升級(Upgrade)消息頭字段的請求。沒有 h2c
的升級令牌的請求可使用一個包含了 Upgrade 消息頭字段的 505(HTTP 版本不支持)狀態碼來拒絕。那些不但願處理 HTTP/1.1 響應的服務器應該在發送了帶有鼓勵用戶在升級了的 HTTP/2 鏈接上重試的鏈接序言以後當即用帶有 REFUSED_STREAM 錯誤碼拒絕該請求的第一份數據流.
不,那是正確的。流 B 的權重爲 4,流 C 的權重爲 12。爲了肯定每一個流接收的可用資源的比例,將全部權重(16)相加並將每一個流權重除以總權重。所以,流 B 接收四分之一的可用資源,流 C 接收四分之三。所以,正如規範所述:流 B 理想地接收分配給流 C 的資源的三分之一。
是的,有可能。即便對於僅使用單個流下載大量數據的客戶端,仍然須要一些數據包以相反的方向發回以實現最大傳輸速度。在沒有設置 TCP_NODELAY(仍然容許 Nagle 算法)的狀況下,能夠傳輸的數據包將被延遲一段時間以容許它們與後續分組合並。
例如,若是這樣一個數據包告訴對等端有更多可用的窗口來發送數據,那麼將其發送延遲數毫秒(或更長時間)會對高速鏈接形成嚴重影響。
存取應用程序數據的方法不少,最簡單的方法是使用 NSS keylogging 配上 Wireshark 插件(包含在最新開發版中)。這種方法對 Firefox 和 Chrome 都適用。
HTTP/2 服務器推送容許服務器向客戶端提供內容而無需等待請求。這能夠提升檢索資源的時間,特別是對於具備大帶寬延遲產品的鏈接,其中網絡往返時間佔了在資源上花費的大部分時間。
推送基於請求內容而變化的資源多是不明智的。目前,瀏覽器只會推送請求,若是他們不這樣作,就會提出匹配的請求(詳見 Section 4 of RFC 7234)。
有些緩存不考慮全部請求頭字段的變化,即便它們列在 Vary
header 字段中。爲了使推送資源被接收的可能性最大化,內容協商是最好的選擇。基於 accept-encoding
報頭字段的內容協商受到緩存的普遍尊重,可是其餘報頭字段可能不受支持。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。