先說一下 HTTP 的發展簡史,以及 HTTP/2.0的優點在哪裏。html
1991年發佈的 HTTP/0.9 版本 是基於 TCP/IP 協議的應用層協議。它不涉及數據包的傳輸,只規定了客戶端和服務器之間的通訊格式,默認使用80端口,該版本極其簡單,只有一個命令 GET , 而且只支持文本傳輸。前端
請求過程: TCP 創建後,客戶端向服務器請求 網頁 如 index.html , 而且協議規定, 服務器只能迴應 HTML 格式的字符串, 不能迴應別的格式。 服務器發送完畢後, 就關閉鏈接。瀏覽器
1996年5月, HTTP/1.0 版本發佈。緩存
首先: 加入了不少格式的內容均可以發送,這使得互聯網不只能夠傳輸文字,還能傳輸圖像、視頻、二進制文件。 經過此次的更新,爲互聯網的大發展奠基了基礎。安全
其次: 除了GET命令,還加入了 POST 、HEAD 等命令, 豐富了瀏覽器與服務器的交互手段。服務器
最後: HTTP 請求和迴應的格式也變了。 除了數據部分,每次通訊都必須包括頭信息(HTTP header),用來描述一些元數據。微信
其餘的新增功能還包括狀態碼、多字符集支持、多部分發送、權限、緩存、內容編碼 等網絡
相比 HTTP/0.9 有巨大的變化。微信公衆平臺
可是, HTTP/1.0 仍是存在一些缺點,其中主要缺點是,每一個TCP鏈接只能發送一個請求。發送數據完畢,鏈接就關閉,若是還要請求其餘資源,就必須再新建一個鏈接。工具
TCP 新建鏈接的成本很高,由於須要客戶端和服務器三次握手,而且開始時發送速率較慢,由於 TCP 經過慢開始啓動。 因此,HTTP/1.0 版本的性能就比較差。 隨着網頁加載的外部資源愈來愈多,這個問題就愈發突出了。
解決每次都要從新創建鏈接的方法是: 在客戶端和服務器端各自都加了一個 Connection: keep-alive 以便請求複用。可是,這個字段不是標準字段, 不一樣實現的行爲可能不一致, 所以不是根本的解決方法。
1997年1月, HTTP/1.1 版本發佈, 只比 1.0 版本晚了半年。 它進一步完善了 HTTP 協議,一直用到了20年後的今天, 直到如今仍是最流行的版本。
加入了一些新的功能如:
持久鏈接
Connection: keep-alive , 即 TCP 鏈接時默認不關閉, 能夠被多個請求複用,不用聲明 Connection: keep-alive。
客戶端和服務器發現對方一段時間沒有活動,就能夠主動關閉鏈接。規範的作法是,客戶端在最後一個請求時,發送 Connection: close , 明確要求服務器關閉 TCP 鏈接。 Connection: close
目前,爲了安全性,對於同一個域名,大多數瀏覽器容許同時創建6個持久鏈接。
管線化:即在同一個 TCP 鏈接裏面,客戶端能夠同時發送多個請求, 這樣就進一步改進了 HTTP 協議的效率。(雖然能夠提升效率,可是支持的不多,用的也很少,確實會提高一些效率,可是而且也存在一些問題,後面HTTP/2.0再說)
Content-Length 字段
一個 TCP 鏈接同時能夠傳送多個迴應,那麼就須要有一種機制,區分數據包是屬於哪個迴應的。這就是 Content-Length 字段的做用, 聲明本次迴應的數據長度。
如: Content-Length: 3000
他告訴瀏覽器,本次迴應的長度是 3000 字節, 後面的字節就屬於下一個迴應了。
在 HTTP/1.0 版本中, Content-Length 字段不是必須的,由於不涉及一次傳多個迴應,或者瀏覽器發現服務器關閉了 TCP鏈接,就代表收到的數據包已經全了。
分塊傳輸編碼
使用 Content-Length 字段的前提條件是, 服務器發送迴應以前,必須知道響應的數據包長度。
對於一些很耗時的動態操做來講,這意味着服務器須要等全部操做完成,才能發送數據,顯然這樣的效率不高。更好的處理方法是,產生一塊數據,就發送一塊,採用「流模式」(stream) 取代 「緩存模式」(buffer)。
所以,HTTP/1.1 版本規定能夠不使用 Content-Length 字段,而使用 「分塊傳輸編碼」(chunked transfer encoding)。只要請求或迴應的頭信息有 Transfer-Encoding 字段, 就代表迴應將由數量未定的數據塊組成。
每一個非空的數據塊以前,會有一個16進制的數值,表示這個塊的長度。最後是一個大小爲 0 的塊, 就表示本次迴應的數據發送完了。
其餘功能
HTTP/1.1 版本還增長了不少動詞方法如:PUT、PATCH、HEAD、OPTIONS、DELETE
另外,客戶端請求的頭信息新增了 Host 字段,用來指定服務器的域名。
有了Host字段,就能夠將請求發往同一臺服務器上的不一樣網站,爲虛擬主機的興起打下了基礎。
缺點
Spriting 是將衆多個小圖片整合成大圖片,而後再拆分,壞處可想而知,每一個網頁需不須要用到那麼多圖片,都須要發送。
內聯(Inlining),簡而言之就是把圖片資源放在 CSS 文件裏面的 URL 裏面,這種缺點和 Spriting 相似。
拼接(Concatenation),若是 js 文件特別多的話,可使用工具把衆多 js 文件整合成一個文件,這樣瀏覽器就只須要下載一次就能夠完成,而不是無數次請求去下載,可是若是 js 的某個代碼被改動,那麼也須要從新下載,這樣會對調試和開發者形成極大的不變。
分片(Sharding),由於 HTTP/1.1 規範提到一個客戶端最多能對同一主機創建有限個 TCP 鏈接。所以,Sharding 就是把服務分散在儘量多的服務器上面。這樣用戶就能夠同時和多臺主機創建不少 TCP 鏈接,從而下降載入時間。
線頭阻塞
雖然加入了持久鏈接,管線化,可是同一個 TCP 鏈接裏面,全部的數據通訊都是按次序進行的。服務器只有處理完一個迴應,纔會進行下一個迴應。若是前面的迴應特別慢,後面就會有不少請求排隊等着。這稱爲「隊頭堵塞」(Head-line blocking)
爲了不這個問題,有兩種方法:一是減小請求數量,二是同時多開持久鏈接。這致使了不少的網頁優化技巧,好比合並腳本和樣式表,將圖片嵌入 CSS 代碼、域名分片等等。
爲了解決此類問題的一些解決方法:
過多的可選項和太多的細節
而且 HTTP/1.1 包含了太多細節和可選的部分,這讓它變得過於龐大。
過多的可選項,這就致使了在一些不經常使用的功能在後來的實現中不多會被支持,而有些最初實現了的功能,卻又不多被使用。
隨着時間的推移,這些當初看似被邊緣化的功能逐漸被用上,客戶端和服務器的互用性問題就暴露出來了。HTTP 管線化(HTTP pipelining) 就是一個很是好的例子。
未能被充分利用的 TCP
咱們能夠經過更好的利用 TCP 來減小傳輸過程當中的暫停,並充分挖掘利用那些本能夠用於發送/接收更多數據的時間。
傳輸大小和資源數量
近年來加載網站首頁須要下載的數據量在逐漸增長,而且已經超過了 1.9MB。而且咱們更關心的是平均每一個頁面爲了完成顯示與渲染所須要的資源已經超過100個了。
明顯的延遲
HTTP/1.1 在網絡延遲方面作的就不盡人意了。部分緣由是 HTTP 管線化(pipelining)還存在不少問題,因此對大部分用戶來講這項技術仍是默認被關閉的。雖然近幾年,咱們的網絡帶寬從原來只有 幾百KB ,如今通常的網絡也能達到 數十MB ,可是 網絡延遲也沒有下降。好比在移動設備上,即便擁有高的鏈接速率,也很難得到優質快速的網絡體驗。
例如:能夠將資源分佈在不一樣的主機上面來創建鏈接,得到更快的速度。
2009年,Google 公開了自行研發的 SPDY 協議, 主要解決 HTTP/1.1 效率不高的問題。
這個協議在 Chrome 瀏覽器上證實可行之後,就被當作 HTTP/2 的基礎, 主要特性都在 HTTP/2 之中獲得繼承。
若是用 Chrome ,就會發現,在百度網站上就有用 SPDY 的例子:
2015年, HTTP/2 發佈。它不叫 HTTP/2.0 ,是由於標準委員會不打算再發布自版本了,下一個新版本將是 HTTP/3。
改進
下降協議對延遲的敏感
修復 pipelining 和 head of line blocking 問題
防止主機須要更高的鏈接數量
保留全部現有的接口,內容,URI 格式和結構
HTTP/2 是一個二進制協議
咱們可使用 Wireshark 這樣的 http/2 解析器來分析和調試協議。
http/2 會發送有着不一樣類型的二進制幀,他們有一些公共字段,一共規範了10種不一樣的幀,其中最基礎的兩種分別對應於 HTTP/1.1 的 DATA 和 HEADERS。
多路複用的流,實現雙向的,實時的通訊,多工。
數據包具備優先級和依賴性,服務器能夠優先處理
頭部壓縮,能夠下降傳輸成本,可是有可能會存在安全問題。
支持 重置 ,就是若是要傳輸一個東西,可是須要傳輸好幾回,而後傳輸了一半以後,接收方忽然不想要了,這個時候能夠發送一個 RST_STREAM 幀來終止。而在 HTTP/1.1 時,則須要斷開整個鏈接。
服務器主動推送,也能夠稱緩存推送
若是客戶端請求一個資源,服務器能夠推斷出來客戶端 請求完此資源後,會再請求的資源,這個時候服務器就能夠主動準備好資源而且一併推送給客戶端。若是客戶端不須要,也能夠發送一個RST_STREAM 幀來終止。
流量控制: HTTP/2 能夠有本身公示的流量窗口,它能夠限制一端發送數據。和 SSH 的工做原理相似。
其中包含了不少信息,其中有 Stream ID SEQ/ACK 等字段
下面這張圖來講明 HTTP/1.1 和 HTTP/2 在性能方面的差異。
文 / blank
編 / 陳皮爽,熒聲
做者過往文章:
要點梳理:TCP 鏈接及常見攻擊手法分析(微信公衆平臺連接)
本文已由做者受權發佈,版權屬於創宇前端。歡迎註明出處轉載本文。本文連接:https://knownsec-fed.com/2018-09-25-guan-yu-http2-de-yan-jiu/
想要訂閱更多來自知道創宇開發一線的分享,請搜索關注咱們的微信公衆號:創宇前端(KnownsecFED)。歡迎留言討論,咱們會盡量回復。
感謝您的閱讀。