http/1.0、http/1.1、http/2都有哪些不同的機制,經歷了哪些變革,對前端優化有什麼樣的影響? ...
本文整理在,我的github 上。歡迎Star。
各版本的http
發展
在HTTP建立之初,主要是為了傳輸超文本標記語言(HTML)文檔。隨著時代的發展,也進行了若幹次演進。下圖是各個版本發佈的時間軸。
目前為止,使用最為廣泛的是http1.1,http1.0應該比較少了,最新的是http2。
這篇博文也主要,圍繞著1.0、1.1、2.0三個版本進行介紹。
http/1.0
http1.0不會復用tcp鏈接,每次請求都會打開、斷開一條鏈接。
如果您看過我前陣子整理的關於TCP的博文,您就會知道,TCP是有延遲響應機制的,每次請求並不會馬上返回。這算是http1.0性能不好的一個原因吧。
http/1.1
http/1.1當前普及程度最高的http版本。
到了http/1.1版本,tcp鏈接可以持久保持了(也就說,一段時間內,一個tcp鏈接會等到同一個功能變數名稱下的所有資源載入完後再斷開。)
在保持tcp鏈接的基礎上,引入了http管道的機制,差點實現了多路復用。
http/1.1 without pipelining(不使用管道)
通過一條tcp鏈接請求資源,只有在上一個請求完成後,才能發出下一個請求。也就是上圖描述的情形。
http/1.1 with pipelining(使用管道)
客戶端不會等待響應,直接併發N個請求。但是,http/1.x有嚴格的串列返迴響應機制。通俗的講就是:請求時,不用等上一個完成;但響應時,必須嚴格按照順序返回。
通過開發者工具,你就可以觀察到這一點。
基於以上描述,使用“ HTTP 管道”技術時,萬一第一個響應時間很長,那麼後面的響應處理完了也無法發送,只能被緩存起來,占用伺服器記憶體,這就是傳說中的“隊首阻塞(head of line blocking)”。
這也是http/1.x下,多數網路體驗不好的原因。
http/2.0
在介紹http/2.0之前,我們來先看一份Akamai公司提供的一個官方演示。
這裡用了361(19*19)張圖片,分別使用http/1.1,http/2.0兩種版本的協議進行對比。可以直觀的感受到,http/2.0比http/1.0快出5倍左右的速度。
考慮到您可能需要分別用開發者工具仔細查看下兩個版本,我已經幫你找好了兩個版本對應的鏈接。(不客氣)
那http/2.0究竟引入了哪些機制、特性才達到目前的加速效果呢?簡答的說可以概括成。
- 二進位分幀層
- 多路復用
- 首部壓縮
伺服器推送(server Push)
二進位分幀層與多路復用
引入了二進位分幀層,就不再是文本傳輸了,而是數據幀(二進位)。
註意:HTTP原本的語義,方法、動詞、首部都不受影響。僅僅是傳輸期間的數據格式變化了。
http/2規定了10種不同的幀。
如上圖,分針層會把 開始行,首部行分割到HEADERS幀,正文實體分割到DATA幀。
TCP 連接在客戶端和伺服器間建立了一條運輸的通道,可以雙向通行,當一端要向另一端發送消息時,會先把這個消息拆分成幾部分(幀),然後通過發起一個流對這些幀進行發送,最後在另一端將同一個流的幀重新組合。
這裡涉及了以下概念。
流:已建立的連接上的雙向位元組流
消息:與邏輯消息對應的完整的一系列數據幀
幀:HTTP/2 通信的最小單位,每個幀包含幀首部
其中幀對數據進行順序標識,這樣瀏覽器收到數據之後,就可以按照序列對數據進行合併,而不會出現合併後數據錯亂的情況。同樣是因為有了序列,伺服器就可以並行的傳輸數據,這就是流所做的事情。
HTTP/2對同一功能變數名稱下所有請求都是基於流,也就是說同一功能變數名稱不管訪問多少文件,也只建立一路連接。同樣Apache的最大連接數為300,因為有了這個新特性,最大的併發就可以提升到300,比原來提升了6倍!
首部壓縮
在伺服器和客戶端各維護一個“首部表”,表中用索引代表首部名,或者首部鍵 - 值對,上一次發送兩端都會記住已發送過哪些首部,下一次發送只需要傳輸差異的數據,相同的數據直接用索引表示即可。
首部壓縮,可以解決http頭臃腫的問題。
伺服器推送(server Push)
伺服器可以對一個客戶端請求發送多個響應。也就是說,除了對最初請求的響應外,伺服器還可以額外向客戶端推送資源。
這裡就涉及到了另一個幀類型:PUSH_PROMISE幀。
舉個慄子,當客戶端請求index.html時,伺服器會同時推送style.css,index.js對應的PUSH_PROMISE幀。客戶端可以直接緩存起來。
基於http/2對前端性能優化的思考
個人覺得前端的性能優化,應該主要從兩個方面。載入速度和流暢運行。
原引,在網上看到的一段話:
網頁不僅應該被快速載入,同時還應該流暢運行,比如快速響應的交互,如絲般順滑的動畫等。
http/1.x的優化方案
當然,今天的主題是討論網路協議,那我們只談載入速度。
基於http1.x的相關特性,可愛的前端們提出了很多頗具成效的優化方案。(精靈圖,多功能變數名稱載入等等)其中,比較著名的雅虎軍規,很多人應道都知道,這裡有一張整理好的圖。
http/2的變革
在http/2的基礎上,很多http/1.x要優化的問題,都不存在了。問題都不存在了,問題的優化方案也就不存在了。
這裡插一句,我始終堅信的一個觀點是:沒有任何優化手段是不需要付出代價的。是藥三分毒,無非是取捨罷了。
1.合併css、js與精靈圖
在http/1.x時代,http並沒有最大程度上利用好tcp鏈接。雖然http/1.1里有了http管道,但其也帶來了隊首阻塞等問題,同時也要受隊列大小的限制。所以我們要通過合併文件的方式減少http鏈接數量。
不錯,減少http請求數量的確能起到優化的作用,但與此同時,也有很多弊端:
- 所有文件合成一個大文件,那不管哪個模塊發生變更,都要整體更新,用戶都要重新下載,無法繼續使用緩存。
- 帶來了額外的維護成本。印象比較深的是維護精靈圖,稍微改一點,就得重新弄。
以上,就是”合併css方案"、“合併js方案”、“精靈圖方案”的優勢與弊端。
- 在http/1.x基礎上,明顯優勢>弊端,所以我們使用這些方案。
- 但http/2,它對tcp鏈接的利用程度已經有了飛躍性的提升。此時這些方案是否優勢>弊端,就值得商榷了。筆者覺得應該正好反過來。優勢<弊端。
2.分功能變數名稱
在http/1.x基礎上,分功能變數名稱有兩個好處。
- 為了繞過瀏覽器對同一功能變數名稱的最大管道限制。可以同時請求更多內容。
- 同一功能變數名稱下的請求報文,會匹配的站點的全部cookie,增大請求報文長度。而很多資源,比如圖片、css是不需要cookie的。
在http/2上,對於這些問題
- 原本就支持多路復用,沒必要分
- 有首部壓縮機制,首部行大點,也就傳一個。
3.介面合併
如果頁面需要多種數據,我們會儘量將數據彙總到一個介面,以減少http請求數量。
這種做法,幾乎違背了各種程式設計規範,比如“單一職責原則”等等,介面很難復用,維護成本高。
這種方案在http/2下,明顯弊端>優勢了。
參考文獻
- [1] 前端開發與 HTTP/2 的羈絆——安利篇
- [2] 假如HTTP/2已經普及
- [3] HTTP相關——http1.0 1.1 1.2、https、加密演算法
- [4] http2.0 --速度與激情
-
插一句《RFC7540》是官方對http2.0規格的描述,比較權威。