请自行准备https证书, 本项目使用了mime 包判断文件类型。
index.html 和 cook.js 和 server.js 放在同一目录下面。
http2 的推送效果如下。
没有推送
可以看见一共请求了2次,第一次加载html,第二次加载cook.js。耗时84ms。
开启推送
开启推送后 加载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 会发现自己已经有了就不在请求了。
stream.pushStream({ ':path': '/cook.js' }, (err, pushStream, headers) => {
if (err) throw err;
sendFile(pushStream, './cook.js');
});
}
});
server.listen(443);