前端進階篇-HTTP/2

瞭解HTTP/2

簡單來講,HTTP/2,是HTTP協議的第二個主要版本。HTTP/2是HTTP協議自1999年HTTP1.1發佈後的首個更新,主要基於google的SPDY協議。 HTTP/2的特色是:在不改動HTTP語義、方法、狀態碼、URI及首部字段的狀況下,大幅度提升了web性能。css

SPDY是谷歌研發的應用層協議,用戶提高web性能。html

HTTP/2和HTTP1.X相比的新特性

  1. HTTP/2多路複用
  2. HTTP/2服務端推送
  3. HTTP/2二級制分幀
  4. HTTP/2首部壓縮

HTTP/2多路複用

線頭阻塞 (Head-of-Line Blocking)

  • HTTP1.0的線頭阻塞發生在客戶端,只有客戶端收到請求結果後纔會發送下一個請求。(會從新創建TCP鏈接)
  • HTTP1.1的線頭阻塞發生在服務端,根據瀏覽器不一樣,客戶端能向同一域名的服務器同時創建多個TCP鏈接,可是服務器必須按照請求的順序返回。(沒必要從新創建鏈接)

HTTP/2經過多路複用解決線頭阻塞問題:

  • HTTP1.x的請求都是基於文本傳輸,服務端一次只能處理一個請求或響應
  • HTTP1.1中支持同時多個請求發送給服務端,但服務端必須按順序返回響應。

HTTP/2的請求再也不基於文本傳輸,具體方式爲:在同一個域名下開啓一個TCP connection,每一個http請求以流(stream)的方式在此鏈接上傳輸,每一個stream是由若干幀(frame) 組成,frame是HTTP/2資源傳輸的最小單元,frame中的字段identifier標識此幀屬於哪個流,identifier相同的frame屬於同一流,服務端將identifier相同的幀解析成可用數據。在這個TCP connection中,同時傳輸了多個流的幀數據,這就是HTTP/2的多路複用。ios

image.png

每個幀(frame) 都包含length、type、flags、stream identifier、frame playload等字段, 這裏說下幀的type字段,在HTTP/2的標準中定義了10種不一樣的幀type。web

  • HEADERS(包含HTTP頭和可選的優先級參數)
  • DATA(流的核心內容)
  • PRIORITY(流的優先級)
  • RST_STREAM(終止流)
  • SETTINGS(設置此鏈接的參數)
  • PUSH_PROMISE(服務器推送)
  • PING(測量RTT)
  • GOAWAY(終止鏈接)
  • WINDOW_UPDATE(協商一端要接收多少字節,流量控制)
  • CONTINUATION(繼續傳輸頭部數據)

frame的PRIORITY字段用於標識流的權重(1-256)和依賴關係,以正確的順序請求資源對於用戶體驗相當重要。瀏覽器

  • 客戶端經過對象的依賴關係告訴服務器哪些資源應該優先傳輸
  • 權重讓服務器知道擁有共同依賴關係資源的優先級

服務器根據依賴關係和權重進行帶寬分配,高優先級的資源得到更多的帶寬。緩存

權重的大致規則不外乎 根文檔 - 樣式文件 - 字體文件 - 腳本文件 - 背景圖 - 圖標文件 - 圖片。 不一樣的瀏覽器規則會有所差別。安全

ios中瀏覽器的資源權重參考:服務器

  1. HTML - 255
  2. CSS - 24
  3. JS - 24
  4. FONTS - 16
  5. IMAGES - 8

ps: 服務端對於高優先級的資源的策略是分配更多的帶寬,可是不會保證此資源必定會優先返回,這是爲了不線頭阻塞cookie

多路複用讓http請求變得廉價,建立一個新流的成本很低,理論上能夠同時發起無限個請求,不過咱們能夠在stream的SETTINGS字段上設置SETTINGS_MAX_CONCURRENT_STREAMS用於限制最大併發數。網絡

HTTP/2服務端推送

HTTP1.x中,咱們經過將重要的js代碼或者css樣式代碼嵌入html頁面中,讓頁面能夠快速響應,可是內嵌代碼最大的弊端是沒法緩存。哪怕只是修改一個小樣式也必須下載整個文件。

這也是其它資源整合的共同弊端,如圖片以base64的方式嵌入代碼、CSS精靈圖(sprite)等,每當修改了精靈圖中的一個小圖,咱們不得不從新下載整張精靈圖。

HTTP/2容許服務端主動推送資源,當TCP connection創建後,服務器能夠主動推送資源而非客戶端發起請求,服務端推送是基於frame的PUSH_PROMISE字段來實現的。並且服務端push的資源是能夠被緩存的。

關於服務端推送一個常見的問題是若是客戶端已經有一份緩存了怎麼辦?

瀏覽器能夠經過PUSH_PROMISE字段判斷資源是否已經緩存,而後經過發送RST_STREAM幀用於終止推送。在這個過程當中,服務端只是推送了資源的地址,並無直接推送資源的實體,這樣的目的也是爲了減小沒必要要的資源傳輸。

HTTP/2規定,由客戶端發起的流的ID(stream identifier)都是奇數,由服務端發起的流ID是偶數。

二進制分幀

HTTP/2其實是對HTTP1的一個數據封裝,本質上沒有改變HTTP1的語義,狀態碼、URI 以及header字段等。

image.png

要實現對HTTP1的封裝,HTTP/2在傳輸層(TCP, UDP 或者SSL/TSL安全協議層)和應用層之間新增一個二進制分幀層,在分幀層中,HTTP/2將全部信息分割成幀(frame),其中原http header信息被封裝到 HEADER 類型的幀中,內容被封裝到DATA類型的幀中。

二進制分幀是多路複用,頭部信息壓縮,服務端推送, 流量控制等HTTP/2功能的基礎。

首部壓縮

爲何要壓縮?

在HTTP1.x中,HTTP協議都是由狀態行,消息頭,主體構成,在傳輸過程當中,主體內容通常都是通過gzip壓縮,或者傳說的自己就是二進制流(視頻,圖片)等,而消息頭和狀態行都是純文本傳輸的。

並且不少消息頭中的字段冗餘如 COOKIE,UserAgent等,浪費了大量帶寬,增長了網絡延時。不少時候請求消息頭的大小甚至超過了主體內容的大小。

壓縮首部體積

HTTP/2經過維護靜態字典和動態字典的方式來壓縮首部

  • 靜態字典中包含了常見的頭部名稱或者頭部名稱和值的組合,如method:GET
  • 動態字典中包含了每一個請求特有的鍵值對,如自定義的頭信息,針對每一個TCP connection,都須要維護一份動態字典。

1:對於靜態字典中匹配的頭部名稱或頭部名稱和值的組合,可使用一個字符表示,如創建鏈接時:

method:GET 可使用 1表示 (徹底匹配)
cookeie: xxx 可使用 2:xxx表示 (頭部匹配)
複製代碼

2:同時將cookeie: xxx加入動態字典中,這樣後續的整個cookie鍵值對均可以使用一個字符表示:

cookeie: xxx 可使用 3表示 (加入到動態字典)
複製代碼

3:對於靜態字典和動態字典中都不存在的內容,使用了哈夫曼(霍夫曼)編碼來壓縮體積。

不是全部的頭部信息均可以被添加到動態字典中,這時就是使用哈夫曼編碼壓縮的場景。

HTTP1中的狀態行信息如Status等在2.0中都以鍵值對的方式放入頭部中,作爲消息頭的一部分。

動態字典會在每一個TCP鏈接上維護一個,且動態字典的內容是根據請求量逐漸累積的。 因此在HTTP/2的網站中,咱們須要作的再也不是整合資源和散列域名了。而是分散資源和使用一個鏈接,如下兩種狀況下瀏覽器會使用一個鏈接:

  1. 同一域名下的資源請求。
  2. 不一樣域名可是同一IP地址,且證書(TSL證書)相同。

總結

  1. HTTP/2只是對HTTP1的封裝,並無改變HTTP1的語義等
  2. HTTP/2新增的二級制分幀是多路複用,服務端推送等功能基礎
  3. HTTP/2經過維護字典的方式壓縮首部體積
  4. HTTP/2的站點中所需的優化手段和HTTP1的區別,不在需求資源整合,而是倡導資源分散(有利於緩存和動態字典積累),不在需求域名散列,而是倡導使用一個鏈接(減小創建TCP鏈接的開銷,減輕服務端壓力,不用維護多個動態字典)
相關文章
相關標籤/搜索