1. 程式人生 > >HTTP2.0 原理詳解

HTTP2.0 原理詳解

不依賴 href 漸進 pre new 進制 四個步驟 回來 stream

影響一個網絡請求的因素主要有兩個,帶寬和延遲。今天的網絡基礎建設已經使得帶寬得到極大的提升,大部分時候都是延遲在影響響應速度。

連接無法復用

連接無法復用會導致每次請求都經歷三次握手和慢啟動。三次握手在高延遲的場景下影響較明顯,慢啟動則對文件類大請求影響較大。

head of line blocking

head of line blocking會導致帶寬無法被充分利用,以及後續健康請求被阻塞。

技術分享
HTTP1.0 -> HTTP1.1

不過pipelining並不是救世主,它也存在不少缺陷:

  • pipelining只能適用於http1.1,一般來說,支持http1.1的server都要求支持pipelining

  • 只有冪等的請求(GET,HEAD)能使用pipelining,非冪等請求比如POST不能使用,因為請求之間可能會存在先後依賴關系。

  • head of line blocking並沒有完全得到解決,server的response還是要求依次返回,遵循FIFO(first in first out)原則。也就是說如果請求1的response沒有回來,2,3,4,5的response也不會被送回來。

  • 絕大部分的http代理服務器不支持pipelining。

  • 和不支持pipelining的老服務器協商有問題。

  • 可能會導致新的Front of queue blocking問題。

HTTP2 VS HTTP1.1

多路復用

多路復用通過多個請求stream共享一個tcp連接的方式,解決了http1.x holb(head of line blocking)的問題,降低了延遲同時提高了帶寬的利用率。

技術分享

壓縮頭部

HTTP/2.0規定了在客戶端和服務器端會使用並且維護「首部表」來跟蹤和存儲之前發送的鍵值對,對於相同的頭部,不必再通過請求發送,只需發送一次。

事實上,如果請求中不包含首部(例如對同一資源的輪詢請求),那麽首部開銷就是零字節。此時所有首部都自動使用之前請求發送的首部。

如果首部發生變化了,那麽只需要發送變化了數據在Headers幀裏面,新增或修改的首部幀會被追加到“首部表”。首部表在 HTTP2.0的連接存續期內始終存在,由客戶端和服務器共同漸進地更新。

技術分享

二進制分幀

在應用層與傳輸層之間增加一個二進制分幀層,以此達到“在不改動HTTP的語義,HTTP 方法、狀態碼、URI及首部字段的情況下,突破HTTP1.1的性能限制,改進傳輸性能,實現低延遲和高吞吐量。”

在二進制分幀層上,HTTP2.0會將所有傳輸的信息分割為更小的消息和幀,並對它們采用二進制格式的編碼,其中HTTP1.x的首部信息會被封裝到Headers幀,而我們的request body則封裝到Data幀裏面。

技術分享

客戶端和服務器可以把HTTP消息分解為互不依賴的幀,然後亂序發送,最後再在另一端把它們重新組合起來。註意,同一鏈接上有多個不同方向的數據流在傳輸。客戶端可以一邊亂序發送stream,也可以一邊接收者服務器的響應,而服務器那端同理。

技術分享

請求優先級

多路復用導致所有資源都是並行發送,那麽就需要「優先級」的概念了,這樣就可以對重要的文件進行先傳輸,加速頁面的渲染。

服務器推送

服務器推送是指在客戶端請求之前發送數據的機制。

另外有一點值得註意的是,客戶端如果退出某個業務場景,出於流量或者其它因素需要取消server push,也可以通過發送RST_STREAM類型的frame來做到。

HTTP2 實踐

這裏使用 Node.js 作為服務器端語言。

1. 生成TLS證書

如果想要在生產環境中使用HTTP2,那麽你可以去這裏生成一個證書。

如果你僅僅開發環境使用,那麽我們可以自己生成一個自簽名的TSL證書。

  1. 安裝OpenSSH

  2. 使用OpenSSH生成私鑰

    openssl genrsa -des3 -passout pass:1234 -out server.pass.key 2048`

    這裏 1234 為私鑰密碼,如果你不想使用密碼,則可以去除私鑰密碼,敲入如下密令:

    openssl rsa -passin pass:x -in server.pass.key -out server.key
  3. 創建 證書簽名請求
    這裏使用無密碼私鑰,如果使用帶密碼私鑰,只需將server.key更換為server.pass.key即可,密令如下

    openssl req -new -key server.key -out server.csr
  4. 創建證書

    openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

通過以上四個步驟,我們得到了三個文件

  1. server.key 你的TSL證書私鑰

  2. server.csr 你的TSL證書簽名請求

  3. server.crt 你的TSL證書

2. 使用Node.js 創建服務器

安裝 node-http2 模塊

npm install http2

創建服務器

var options = {
  key: fs.readFileSync(‘./server.key‘),
  cert: fs.readFileSync(‘./server.crt‘)
};

require(‘http2‘).createServer(options, function(request, response) {
  response.end(‘Hello world!‘);
}).listen(8080);

啟動服務器

node index.js

使用瀏覽器訪問

http://localhost:8080

到此,一個簡單的Demo就完成了。

Demo源碼下載

點擊這裏訪問完整Demo

https://github.com/zhanyouwei...

測試結果對比

技術分享

技術分享

通過上面兩張截圖可以發現,使用了HTTP2後,同樣的請求,在數據傳輸大小與速度上都有非常大的提升,幾乎可以預見,不久的將來,HTTP2將會大放異彩。

HTTP2.0 原理詳解