自2013年HTTP/2推出以來,HTTP/2已經得到了長足發展,瀏覽器平臺基本提供了HTTP/2的支援,知乎,豆瓣等國內大型平臺也已經部分切換到HTTP/2了。
HTTP/2優點
多路複用請求 對請求劃分優先順序 壓縮HTTP頭 伺服器推送流
HTTP/2支援情況:
chrome,firefox,ie11(win10版)都已經支援
詳情可檢視:caniuse.com/#search=htt…
HTTP/2快取情況:
HTTP/2並不像我們所在網上搜尋到的那樣不能快取,只是需要在伺服器端配置快取,如:"expires":"Tue, 09 Oct 2018 11:27:20 GMT"。
測試方法:
在地圖中應用時,載入圖片有兩種方式,一種是直接在img例項上設定url,讓瀏覽器自己去觸發訪問圖片,另一種是通過ajax載入(xhr.responseType = 'blob';,因為ajax請求過來的都是二進位制字串,所以要解析,後端讀取檔案和返回檔案內容時同樣要設定引數為binary),請求的結果通過img.src = window.URL.createObjectURL(data);解析成圖片url。
根據兩種載入方式,我構造了四組測試程式碼,並分別選取了每個圖片大小為237KB和2KB的大小兩組圖片進行測試:
- HTTP/2&&AJAX載入
- HTTP/2&&瀏覽器載入
- http1.1&&AJAX載入
- http1.1&&瀏覽器載入
其它注意事項
使用瀏覽器訪問的時候一定要用https協議訪問,http協議訪問不到
chrome允許本地https,進入chrome://flags/#allow-insecure-localhost設定其值為enabled
chrome裡network內列標題上右鍵可開啟protocol列檢視請求的協議是不是h2
初次載入時會自動載入favicon.ico檔案,可能會導致出錯
程式碼實現
localhost-cert.pem
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIJALUOjGkvsHSZMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xODAxMjUwNTMxMDFaFw0xODAyMjQwNTMxMDFaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBANRicexesNtTbjVnxKyEWalFovZUEYQ/FRjArJAndaEBSVlsrTRFrp3nEUNx
6O6EUM4SrfOTCfEW6Pi9YqH8wVk8/G3BCOG99as6GIHabkbC79UiNdDhAQLr10+g
gaXl+QYxvGEvk/Qb/9LRFc3EqurVNmKdEPVUUpgcR8dL9SnOguLoSuKA2U+5AYLm
lX0lUG2S34o+H+Ck6dC8IK94uFNpyNPvd4xf+xEERBm7Q5IVLjZ0D40luF1g7S9L
IltT8BTYeYeCWGoNifQccS/5qfwuK3C7ga29lduJKNmDzhiKCCTelU92+COYisiE
sgYK4fbFnGHbiETFu87IJsABD2kCAwEAAaNQME4wHQYDVR0OBBYEFOtVzO6eutPf
g85CvFu8q7fA5EzxMB8GA1UdIwQYMBaAFOtVzO6eutPfg85CvFu8q7fA5EzxMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFC+aeqkhe0YugcIP4cVCpPI
6xcfG0IZ82I94DhejVmsio2zP3kekR7ekzY4z28d6Kz03X0j+ll71xxZKZljnl3K
4C7oiBzj8ypCykXj03JDWNQ3sZNycfF/53OOk5Gu18qQ77TjqDpOGKU0xL45SmoB
oH/X2e9ccygMKOAAKqjT4ZVxksShC+tE+ij8ocBRfkMnJw0mfNAPlSjYw/Ho6WLJ
qlz0KyY5LkVHJbznXbN6S1K2FujJdyf7CkxMSb2bilDk8YvtXp8wFZg2R7Phi+dt
gbEx47N2hM0tLF0yPjAyBa+JKC2rG+/AS5ZfcTjYG3o+M84Y6l6QL3AXacn5L0k=
-----END CERTIFICATE-----
複製程式碼
localhost-privkey.pem
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDUYnHsXrDbU241
Z8SshFmpRaL2VBGEPxUYwKyQJ3WhAUlZbK00Ra6d5xFDcejuhFDOEq3zkwnxFuj4
vWKh/MFZPPxtwQjhvfWrOhiB2m5Gwu/VIjXQ4QEC69dPoIGl5fkGMbxhL5P0G//S
0RXNxKrq1TZinRD1VFKYHEfHS/UpzoLi6ErigNlPuQGC5pV9JVBtkt+KPh/gpOnQ
vCCveLhTacjT73eMX/sRBEQZu0OSFS42dA+NJbhdYO0vSyJbU/AU2HmHglhqDYn0
HHEv+an8Litwu4GtvZXbiSjZg84Yiggk3pVPdvgjmIrIhLIGCuH2xZxh24hExbvO
yCbAAQ9pAgMBAAECggEANdwxX+wzlat2y3xhWA7IXjEWvrlbJ9qHkxtpp7UaE5ar
702sLxFs0waCTkRY+gP8KgZ6rsafQtC4jDwbA1GCBwt8SKkng3gVETNOe7/VL4TI
JZjjZPFqvD7q/3qI5nWHzZZXW54hO0rOebwkd2ZkoeEoRaHnZw/XUlP5sAUHS25p
LcmLcsY3j4vNG3px2K6yucfQwjidV0wSkh+xx5BXTwN65E3uwhBlu8DuV1G/Rv/H
/jXtX3FtF5tqGI/n4RtXGFmfv/ObbdICSxKFoprfv+fQaCk8NDm0uUadPHEOg5Yt
nTu6+52PEneo1dKR++1YVjHQGXqeW3xyuxuJEj6xwQKBgQD36qqkJ4Fo8+HhA1Ia
mKjt53ZItgRb1ecCIckWKG321ohCsVQB4GcNoN75dLt5uHtulcV4RjjK+mUJvQpD
iMnKdXcoJNzfdz0zqqeMH6grCs5FRqkj7UNhqtuSm9z/sQNjpcnE8gUOoA1hGQlA
JYIDcpTv0FkJGF72pyA+Q6Z05QKBgQDbTzIcWAW/wAg42K24hLtM4/hSaGHxovbt
7x1e0ymUVfXja3tvgrR6ptEI9jP+8tCJn9n4+TBifwKEMZdOU1JicFvVNjvRCEtg
INdm/Le8gzfYnCcfv0b9P1of9ZdbjHuYbe6sJZ2dm1h3auqojO/R1M7MT0vJkaYy
ZpbG8O2sNQKBgQCHCkoc1HAHLSESoe5tEk6iF/w0KwFAzMjiPmj8KtWLKNxcB5+M
ziEUKVaLZuxfpv+FAwvnMcjpt26l2VTn6HCSWV2ofjvZdWfe5swQ5YWCvIYS8iRb
r3eOkbS8rS26ET+ZXcsD/hiHGONwymRhjoy9OAKshj6ZV68Sh4JmqA7ZiQKBgFnQ
3VzuT6xwIO3nD356HZsn4hMd3L7xVt+rBgRHxseRTNqOskbA6NkyaHmbG0BWgUFb
zhFBPKeaDJXHGYhiZ2MZUQLI60Z4dyYvTQhIh5cUxlJX4U4HMDOXNnnQQuSjbBrJ
Ku4lmZ9qd5iwmNnennj5Bph2ATvUApSxnx5qnWvhAoGAPKLPKCuVoJS6FUZXl4ef
Pm0JYq+vl301wFAs9+4sf9kB3gA+xRFt8XHOmhaCgTDTea/EvSCR4FDO1BZgKpre
iyeQ5YdPYJ7sVq0TgQLCMzyqopG2f2/mmnJ/jzZhOp2C+gtqO0sKko6MZZTBEs3G
M94dSazKORHbqv9K6v49nls=
-----END PRIVATE KEY-----
複製程式碼
index.js
const http2 = require('http2');
const fs = require('fs');
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
});
server.on('error', (err) => console.error(err));
server.on('socketError', (err) => console.error(err));
server.on('request', (request, response) => {
console.log('./images'+request.url);
//格式必須為 binary 否則會出錯'./images'+request.url
var content = fs.readFileSync('./images'+request.url,"binary");
response.writeHead(200, {
"Content-Type": "image/png",
"expires":"Tue, 09 Oct 2018 11:27:20 GMT",
"Access-Control-Allow-Origin": "http://localhost:8080"
});
response.write(content,"binary"); //格式必須為 binary,否則會出錯
response.end();
});
server.listen(8443);
複製程式碼
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTTP/2測試</title>
<script src="./http.js"></script>
</head>
<body>
123
<div id="imgContainer"></div>
</body>
<script>
for(var i=1; i<16; i++){
// GET('https://localhost:8443/'+i+'.png',function(response){
// drawImg(response);
// });
// GET('http://localhost:8080/http2test/images/'+i+'.png',function(response){
// drawImg(response);
// });
// var myImage = new Image();
// myImage.src = 'https://localhost:8443/'+i+'.png';
// document.body.appendChild(myImage);
var myImage = new Image();
myImage.src = 'http://localhost:8080/http2test/images/'+i+'.png';
document.body.appendChild(myImage);
}
function drawImg(data){
var img = new Image();
img.src = window.URL.createObjectURL(data);
img.onload = function(){
window.URL.revokeObjectURL(img.src);
}
document.body.appendChild(img);
}
</script>
</html>
複製程式碼
http.js
/**
* 發起非同步請求的庫
*/
function GET(url,callback){
var xhr = new XMLHttpRequest();
xhr.open('GET',url,true);
xhr.responseType = 'blob';
xhr.onload = function(){
if(xhr.readyState === 4 && xhr.status >= 200 && xhr.status <300 && xhr.response){
callback(xhr.response);
}
}
xhr.send();
}
複製程式碼
rename.js(用於快速生成大量不同名的相同檔案)
const fs = require('fs');
var path = './images';
var dirs = fs.readdirSync(path);
var n = 0;
for(let i in dirs){
var filename = dirs[i].split('.');
var type = filename[filename.length-1];
if(type=='png'){
fs.renameSync(path+'/'+dirs[i],path+'/'+n+'.png');
n +=1;
}else{
fs.unlinkSync(path+'/'+dirs[i]);
}
console.log('處理完成:'+dirs[i]);
}
複製程式碼
完整程式碼地址: 可以直接跑起來的http/2與http/1.1的對比測試
測試結果:
因為本地載入實在太快,為儘量模擬生產環境網路情況,以下測試都是使用Chrome的fast3G模式。
型別 | 請求方式 | 大(237kb)小(2kb)檔案 | 檔案數 | 載入時間 |
---|---|---|---|---|
HTTP/2 | 瀏覽器載入 | 小 | 40 | 2.81s |
HTTP/1.1 | 瀏覽器載入 | 小 | 40 | 5.89s |
HTTP/2 | AJAX | 小 | 40 | 2.49s |
HTTP/1.1 | AJAX | 小 | 40 | 5.82s |
HTTP/2 | 瀏覽器載入 | 大 | 40 | 52.59s |
HTTP/1.1 | 瀏覽器載入 | 大 | 40 | 52.57s |
HTTP/2 | AJAX | 大 | 40 | 52.66s |
HTTP/1.1 | AJAX | 大 | 40 | 52.58s |
由此可見: _HTTP/2的優勢主要體現在大量小圖片的載入上,對於少量大圖片的載入並不佔太大優勢,並且,網路條件如果非常好的時候,由於載入非常快,HTTP/2也不能體現出優勢。
HTTP/2在WebGIS等地圖應用上的設想:
WebGIS以瓦片技術得以普及,瓦片即請求和檔案,每載入一個瓦片都需要請求一次伺服器上的圖片或其它格式的檔案。地圖瓦片大多為40kb左右的png檔案,且一次載入數量都在20左右。由於http1.1本身的限制,瀏覽器只能同時載入6個檔案(不同的瀏覽器策略額細微的差別),當地圖瀏覽視窗移動時,前端會同時傳送大量AJAX請求來載入瓦片。 此時瀏覽器就會受到阻塞,需要先等待佇列前面的檔案載入完成才能載入後面的檔案。
HTTP/2的併發特性正好能解決此問題,也正好能對應這種場景。
高德地圖部分使用了HTTP/2, 谷歌地圖全部使用了HTTP/2 百度地圖還沒有使用HTTP/2 mapbox沒有使用HTTP/2
目前唯一的問題是需要統計ie11的市場佔用率,若佔用率還是太高切換之後處理起來是個麻煩事。
參考:
Node.js中HTTP/2的使用:nodejs.org/api/http2.h…
PHP中HTTP/2深入分析:www.phpchina.com/article-402…