扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
这篇文章给大家分享的是有关nodejs如何实现http2推送信息的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
10年积累的成都网站设计、网站制作、外贸营销网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有沙河免费网站建设让你可以放心的选择与我们合作。
在http1.x时代,服务器是不能向客户端推送消息的,而在http2里面这成为了一个标准。
HTTP/2被设计为解决HTTP/1.x的许多缺陷。服务器不能向客户端推送消息就是一个缺陷,我们用一个案例来解释一下。
如果一张网页中依赖了很多资源,如js、css、图片等。在HTTP/1.x中浏览器获取HTML后,开始快速扫描整张网页,然后去下载js和css等一些关键资源。而这个过程中有一个瓶颈,那就是浏览器如果要扫描html的话必须先加载html,只有加载完html才能扫描出关键资源,而在加载html的过程中,css和js的加载只有等到html加载完成后才能下载,这里产生一个空闲时刻。HTTP1.x的请求流程如图:
观察图片发现,css和js必须等到html加载完成后,浏览器才能去请求css和js资源。
为了改善延迟,HTTP/2引入了server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前。一个服务器是清楚的知道一个页面需要哪些附加资源的(当然这些需要开发者的配置),在它响应浏览器第一个请求的时候,可以同步开始推送这些资源。
HTTP2请求流程如图:
对比两张图我们发现,在http2协议下,如果浏览器请求一张网页,服务器在返回html资源的时候,还会将css和js资源一同返回。
这就是http2的推送过程,这里是如何实现的呢?这里需要注意,在上篇文章中,我们了解到http2是全双工通信,并且是基于stream的方式传输信息的,当浏览器请求某个网页时,在建立了tcp链接通道后,这个通道是全双工通信的实现(全双工的意思就是通道可以同时处理客户端的请求和服务端的响应),服务端在响应html内容时,同时将css和js以stream的形式push到客户端。
具体实现流程图如下:
从上文中,我们了解到虽然html信息和css,js一起返回给客户端,但是这里需要注意,虽然是一起返回,但是用的是不同的stream,返回html部分有专门的的stream,返回css和js也有相应的stream,可以理解为从单位到家只有一条路,但是可以乘坐不同的公交车。
从上图中我们可以看到一点有意思的规定,推送数据的流的id是偶数,而请求流并针对请求流响应的流的id是奇数,我猜测这可能是为了方便区分推送流和非推送流的区别。
接着我们利用nodejs的http2模块来实现一下http2的推送功能,代码如下:
const http2 = require('http2');
const fs = require('fs');
const PORT = 8443;
//证书与私钥
const key =fs.readFileSync('./server.key');
const cert= fs.readFileSync('./server.crt');
//1、创建服务器
const server = http2.createSecureServer({
key,
cert
},onRequest);
//2、启动服务器
server.listen(PORT, (err) => {
if (err) {
console.error(err)
return
}
console.log(`Server listening on ${PORT}`)
})
//3、设置request事件函数
function onRequest(req,res){
const reqPath = req.url === '/' ? '/index.html' : req.url
//打印请求流的id和响应流的id
console.log("req.stream.id:",req.stream.id);
console.log("res.stream.id:",res.stream.id);
//判断是否是首页
if (reqPath === '/index.html') {
//推送1.js
res.stream.pushStream({ ':path': '/1.js' }, (err, pushStream, headers) => {
if (err) throw err;
pushStream.respond({ ':status': 200 });
console.log("pushStream:",pushStream.id)
pushStream.end("console.log(1)");
});
//推送2.js
res.stream.pushStream({ ':path': '/2.js' }, (err, pushStream, headers) => {
if (err) throw err;
console.log("pushStream:",pushStream.id)
pushStream.respond({ ':status': 200 });
pushStream.end("console.log(2)");
});
const fd = fs.openSync('./index.html', 'r');
const stat = fs.fstatSync(fd);
const headers = {
'content-length': stat.size,
'last-modified': stat.mtime.toUTCString(),
'content-type': 'text/html'
};
res.stream.respondWithFD(fd, headers);
}else{
res.end("404")
}
}
然后我们再来看一下index.html的代码:
Document hello world
index.html的代码:很简单,一张网页引入了1.js和2.js。
服务端代码:使用http2模块创建服务器和https、http模块差不多,只不过浏览器在支持http2的时候要求必须设置证书,所以我们需要配置证书和秘钥。
在request事件函数中,我们判断请求的url是否是首页,如果是首页的话,我们通过res.stream.pushStream这个方法配置推送信息,本质上是配置一个tream,这个stream是Http2Stream 类的实例,res.stream.pushStream需要两个参数,第一个参数是一个对象,在这个对象中配置这个流的path,客户端可以通过这个path使用这个流。
第二个参数为一个回调函数,回调函数第一个参数是err,第二个参数是一个stream,这个stream也是Http2Stream 类的实例。
这个stream是如何设置的呢?我们通过stream对象上的两个方法来设置,respond方法设置stream的头部信息,end方法设置stream的body信息,他们分别对应流中的header帧和body帧。
设置完这两个需要被推送的流之后,再来设置主流html的响应流,这里我们使用strem实例的另外一个方法respondWidthFD来设置响应流。这个方法需要设置两个参数,第一个参数为文件描述符,第二个参数为header信息。文件描述符中存储着流的主体信息,header中保存了流的响应头信息。
从stream两组设置方法,我们可以看出流至少包含两部分信息,header帧和body帧。
代码中我们分别打印了流的id值,我们运行代码看一下打印结果,结果如图:
我们可以看到这和我们前面说的一样,推送流的id是偶数设置,非推送流的id为奇数。
然后我们看一下浏览器中network的截图:
我们看到所有资源都是用http2协议进行请求响应的,而1.js和2.js是服务器在响应html的时候同时push过来的,时间只有1ms。
总结一下:本篇文章主要讲了http2的推送原理,以及如何使用nodejs的http2模块搭建一台http2服务器来实现推送功能。
这里需要注意的几点如下:
1、http2的推送是基于流和全双工通信
2、推送流的id是偶数,非推送流的id为奇数。
3、服务端推送的内容是基于客户端的需要,这里需要前后端工程师通力合作。
4、在推送数据时尽量推送关键性资源,如css、js,关键的背景图等等,而非关键性资源尽量不要推送。
5、nodejs中stream实例配置的两种方式,respond和end或者respondWidthFD,不论哪种方式都需要设置头信息和body信息。
感谢各位的阅读!关于“nodejs如何实现http2推送信息”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流