請自行準備https證書, 本項目使用了mime 包判斷文件類型。
index.html 和 cook.js 和 server.js 放在同一目錄下面。
http2 的推送效果如下。
沒有推送

QQ圖片20181102171850.png
可以看見一共請求了2次,第一次加載html,第二次加載cook.js。耗時84ms。
開啟推送

QQ截圖20181102172235.png
開啟推送后 加載cook.js 變成了 Push, 并且 加載cook.js耗時變成了 2ms。共耗時47ms。
注意事項
啟動項目后使用https 訪問你的服務地址而不是 http。 一般瀏覽器輸入地址默認為http。
例如我的代碼訪問地址 https://127.0.0.1。
想實驗推送效果記得清除瀏覽器緩存。
下面是代碼。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>456</h1>
<script src="./cook.js"></script>
</body>
</html>
cook.js
console.log(123)
server.js
const http2 = require('http2');
const fs = require('fs');
const mime = require('mime');
const options = {
key: fs.readFileSync('bq.key'),
cert: fs.readFileSync('bq.crt')
};
const server = http2.createSecureServer(options);
server.on('error', (err) => console.error(err));
function getHead(fd, path,callBack) {
fs.fstat(fd, function (err,stat) {
if (err) {
stream.end('notFound');
return;
}
const head = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': mime.getType(path)
};
callBack(head);
});
}
function sendFile (stream, path) {
fs.open(path, 'r', (err, fd) => {
if (err) {
stream.end('notFound');
return;
}
try{
getHead(fd, path,function (head) {
stream.respondWithFD(fd, head, { waitForTrailers: false });
stream.on('close', () => fs.closeSync(fd));
});
}catch (e) {
console.log(e);
}
});
}
server.on('stream', (stream, headers) => {
let path = headers[':path'];
if (path === '/') {
path = '/index.html';
}
path = '.' + path;
sendFile(stream, path);
// 當請求的是index.html, 把cook.js 推過去。
if (path === './index.html') {
// stream.pushStream({ ':path': '/cook.js' }) 這里的的path 是瀏覽器將會請求的文件地址。
// 把它推給瀏覽器后,瀏覽器解析html 后請求cook.js 會發(fā)現自己已經有了就不在請求了。
stream.pushStream({ ':path': '/cook.js' }, (err, pushStream, headers) => {
if (err) throw err;
sendFile(pushStream, './cook.js');
});
}
});
server.listen(443);