详解基于节点。js的HTTP/2服务器实践

  

虽然HTTP/2目前已经逐渐的在各大网站上开始了使用,但是在目前最新的node . js上仍然处于实验性API,还没有能有效解决生产环境各种问题的应用示例。因此在应用HTTP/2的道路上我自己也遇到了许多坑,下面介绍了项目的主要架构与开发中遇到的问题及解决方式,也许会对你有一点点启示。

  

  

虽然W3C的规范中没有规定HTTP/2协议一定要使用ssl加密,但是支持非加密的HTTP/2协议的浏览器实在少的可怜,因此我们有必要申请一个自己的域名和一个ssl证书。

  

本项目的测试域名是<代码> you.keyin。我>         sudo certbot certonly——独立- d you.keyin.me      

输入必要信息并通过验证之后就可以在<代码>/etc/letsencrypt/生活/you.keyin。我/<代码>下面找到生成的证书了。

  

  

亚是一个非常简洁高效的node . js服务器框架,我们可以简单改造一下来让它支持HTTP/2协议:

        类KoaOnHttps延伸高雅{   构造函数(){   超级();   }   选项(){   返回{   关键:fs.readFileSync (require.resolve (“/etc/letsencrypt/生活/you.keyin.me/privkey.pem ')),   证书:fs.readFileSync (require.resolve (“/etc/letsencrypt/生活/you.keyin.me/fullchain.pem '))   };   }   听(args) {   const服务器=http2.createSecureServer(这一点。选项,this.callback ());   返回server.listen (…args);   }   重定向(args) {   const服务器=http.createServer (this.callback ());   返回server.listen (…args);   }   }      const应用=new KoaOnHttps ();   app.use (sslify ());//?   app.listen(443年,()=比;{   记录器。ok(应用程序开始:,“https://you.keyin.cn”);   });//获得所有的http请求,将他们重定向到https   app.redirect(80年,()=比;{   记录器。ok (http重定向服务器开始,' http://you.keyin.me ');   });      之前      

上述代码简单基于高雅生成了一个HTTP/2服务器,并同时监听80端口,通过sslify中间件的帮助自动将HTTP协议的连接重定向到https协议。

  

  

静态文件中间件主要用来返回url所指向的本地静态资源。在http/2服务器中我们可以在访问html资源的时候通过服务器推送(服务器推送)将该页面所依赖的js \ css \字体等资源一起推送回去。具体代码如下:

        const发送=要求(“koa-send”);   const记录器=要求(“. ./util/记录器”);   const{推,acceptsHtml}=要求(“. ./util/助手”);   const depTree=要求(“. ./util/depTree”);   模块。出口=(root=")=比;{   下一个异步函数返回服务(ctx) {   让做=false;   如果(ctx)。方法===巴贰眧 | ctx。方法===玫健?{   尝试{//当希望收到html时,推送额外资源。   如果(/(\ . html | \/\ w - *)美元/test (ctx.path)) {   depTree。currentKey=ctx.path;   const编码=ctx。acceptsEncodings (gzip,“缩小”,“身份”);//服务器推送   (const文件的depTree.getDep ()) {//服务器推送之前必须响应!//https://huangxuan.me/2017/07/12/upgrading-eleme-to-pwa/fast-skeleton-painting-with-settimeout-hack   推动(ctx.res。流、文件、编码);   }   }   做=等待发送(ctx, ctx。路径,{根});   }捕捉(err) {   如果犯错。地位!==404){   logger.error(错);   把犯错;   }   }   }   如果(!){   等待下一个();   }   };   };   之前      

需要注意的是,推送的发生永远要先于当前页面的返回。否则服务器推送与客户端请求可能就会出现竞争的情况,降低传输效率。

  

  

从静态文件中间件代码中我们可以看的到,服务器推送资源取自depTree这个对象,它是一个依赖记录工具,记录当前页面<代码> depTree。currentKey>         const记录器=要求(“。/记录器”);      const db=新地图();   让currentKey='/';      模块。出口={   得到currentKey () {   返回currentKey;   },   设置currentKey(关键="){   currentKey=this.stripDot(关键);   },   stripDot (str) {   如果(str)返回”;   返回str.replace(/索引\。html/美元”).replace (/\。/g,“-”);   },   addDep (filePath、url、关键=this.currentKey) {   如果(!关键)返回;   关键=this.stripDot(关键);   如果(! db.has(键)){   db。集(关键,新地图());   }   const keyDb=db.get(关键);      如果(keyDb。大小祝辞=10){   记录器。警告(“推动资源限制超过”);   返回:   }   keyDb。集(filePath url);   },   getDep(关键=this.currentKey) {   关键=this.stripDot(关键);   const keyDb=db.get(关键);   如果返回[](keyDb==定义);   const ret=[];   (filePath、url) (const的keyDb.entries ()) {   ret.push ({filePath、url});   }   返回受潮湿腐烂;   }   };      

详解基于节点。js的HTTP/2服务器实践