原文:http://www.peep-squirrel.com/itcontent-2500617.htmljavascript
隨着 HTTP/2 規範的確認,以及主流瀏覽器(Chrome、Firefox、IE11)對其的全面支持,是時候採用新協議了。看了不少博文跟官方說明,在此作個總結,css
一句話評價:預先加載,合併請求,縮小數據,提高性能。html
HTTP 1.1時代,每一個TCP鏈接一次只能下載一個資源,好比瀏覽器發送一個請求獲取index.html
的數據,服務端收到後只會返回index.html
,隨後瀏覽器會解析index.html
,若是裏面含有<link rel="stylesheet" href="xxx.css">
或<script src="app.js"></script>
,則會再次向服務器發送請求,獲取xxx.css
和app.js
的數據。 這一過程會產生 三個性能問題:前端
index.html
裏含有多個js和css文件,請求數則隨之增長,從而致使在TCP往返鏈接所耗費的時間增多。index.html
與內部的資源文件之間會產生了一個延時,而非同步獲取。因爲上述問題,也就催生出了 HTTP/2。在HTTP/2中,多個請求是能夠合併爲一個的,以下圖,多個數據請求容許在同一路中傳輸(Multiplexed),這樣也就能夠解決了 問題1。java
而由於是同一個請求,所以 HTTP頭信息 只須要有一個就足夠,下圖可看出,HTTP/2中一個請求頭中容許有多個方法,既能夠GET,也能夠PUT,在切換到下一個方法時,只須要獲取數據便可,而不用再次獲取頭信息。node
並且,HTTP/2將頭信息進行了壓縮(參見HPACK),進一步的減小了頭信息的大小,所以 問題2 獲得瞭解決。git
同時,HTTP/2 新加入了 PUSH
方法,該方法的主要做用就是讓服務器試探性的去推送信息給客戶端,如 問題3 中所述狀況,當請求index.html
時,服務器在返回index.html
的同時,會主動把xxx.css
和app.js
一同發送給瀏覽器。這樣當瀏覽器解析DOM,準備發送請求獲取xxx.css
和app.js
的時候,也許兩個資源已經下載完了,只須要從緩存中獲取便可。這樣就大大減小了網絡請求的時間。github
雖然HTTP/2是在協議方面的改進,且但其機制也對目前前端的部分優化方案產生必定影響。web
如上所述, HTTP/2 針對多個請求進行了優化,所以以前咱們在前端中所作的 關於減小HTTP請求的最佳實踐都再也不適用,如合併JS、CSS文件(Concatenation),多個圖片或圖標合併(Spriting),將較小的JS或CSS文件內嵌到HTML中(Inlining),合併HTML文件(Vulcanize),根據 此網站 的測試結果顯示,在使用HTTP/2後,合併爲一個大文件的加載時間反而會比不合並更長。chrome
如上圖所示,其中TTFB時間明顯減小,所謂TTFB(Time To First Byte),即從瀏覽器發送請求開始,到接受到來自服務器的返回的第一字節信息(HTTP頭信息)結束,之間所耗費的時間。這裏就會包含 TCP鏈接往返(round trip)+服務器處理時間(如SQL執行)。 由於瀏覽器在第一次發送請求後,服務器已經預先把其餘資源文件一同推送給了瀏覽器,所以後續的資源請求中,TTFB的時間獲得了縮小。
有些可能會問,那是否是用了 HTTP/2 後,資源文件也不須要壓縮了呢? 答案是No,壓縮文件仍是有必要的,畢竟獲取一個小文件的時間比大文件更短,HTTP/2並不會幫你自動壓縮文件。
能夠看出,HTTP/2 目的之一,就在於想把開發環境與生產環境的部署儘可能保持一致,減小由於打包合併而產生一些沒必要要的麻煩。
目前一部分主流網站已經採用了 HTTP/2,而不少語言也已經有實施方案,詳細的可見該 列表, 本文只介紹下如何用 NodeJS 搭建 HTTP/2 站點。
雖然目前規範中並無達成一致意見來決定 HTTP/2 是否須要加密( Encryption ),但目前主流的實施方案都是須要加密的(如SSL/TLS),所以,如同 HTTPS,HTTP/2 一樣須要建立公私密鑰,來搭建站點。
建立Key:
openssl req -new -newkey rsa:2048 -nodes -keyout localhost.key -out localhost.csr
在輸入完身份信息後,輸出證書:
openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt
若是是初次使用npm安裝,則初始化npm依賴管理:
npm init
此時則會在當前目錄中,生成一個package.json
文件。
安裝http2包:
npm install http2 –save
新建app.js
文件:
var https = require('http2'); var fs = require('fs'); var options = { key: fs.readFileSync('localhost.key'), cert: fs.readFileSync('localhost.crt') }; https.createServer(options, function(request, response) { fs.readFile(__dirname + request.url, function (err,data) { if (err) { response.writeHead(404); response.end(JSON.stringify(err)); return; } response.writeHead(200); response.end(data); }); }).listen(8080);
這樣就搭建完畢,運行便可看到結果
node app.js
若是想確認是否真的採用了 HTTP/2, 只須要在Chrome Dev Tools > Network中,新增 Protocol,便可看到結果:
2015-12-25 更新:
另外注意一點,若是你是從http轉向https,須要在服務端/客戶端作個重定向,保證用戶訪問的站點是https而不是http。
// Redirect from http port 80 to https var http = require('http'); http.createServer(function (req, res) { res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url }); res.end(); }).listen(80);
或者在頁面端:
var host = "YOURDOMAIN.github.io"; if ((host == window.location.host) && (window.location.protocol != "https:")) window.location.protocol = "https";
並且一旦搭建了https,頁面內部全部的外部資源都必須實施https,不然會瀏覽器阻攔:
Mixed Content: The page at 'https://localhost:8080/index.html' was loaded over HTTPS, but requested an insecure script 'http://hectorguo.com/Universities-in-US/app.min.js'. This request has been blocked; the content must be served over HTTPS.
PUSH 是 HTTP/2 的新方法,雖然可讓服務端預先推送資源給客戶端,但並非說只要使用該方法性能就會提高,有時反而會降低。目前官方還未公佈最佳實踐方法,所以並不建議在生產環境中運用,但能夠在開發環境下體驗。
Google提供了一個 SimpleHttp2Server 來簡單搭建 HTTP/2 並使用 PUSH 方法,NPM中也提供了一個 http2-push-manifest 包,能夠自動檢測 html文件中的請求資源,方便服務端識別須要PUSH的文件。
目前各大瀏覽器對 HTTP/2 的支持度以下:
能夠看出基本能夠不用擔憂瀏覽器的支持度問題,並且因爲與HTTP 1.1的API一致,只要 服務端部署完成,便可無縫體驗。
Chrome有個 插件,能夠簡單的監測站點是否採用了 HTTP/2, 通過一些主流網站的觀察,發現國外站點的部署效率的確要高不少。
Google、Twitter、YouTube目前都採用 HTTP/2 (藍色⚡️表明H2)
而國內看了下,百度,必應都木有采用,而淘寶採用了SPDY 3.1(能夠看做H2的前一代,綠色⚡️)