关于HTTP2的新特性,读着可以参看我之前的文章,这里就不在多说了,本篇文章主要讲一下server push这个特性。
HTTP,HTTP2.0,SPDY,HTTPS你应该知道的一些事
简单来讲就是当用户的浏览器和服务器在建立链接后,服务器主动将一些资源推送给浏览器并缓存起来,这样当浏览器接下来请求这些资源时就直接从缓存中读取,不会在从服务器上拉了,提升了速率。举一个例子就是:
假如一个页面有3个资源文件 index.html , index.css , index.js ,当浏览器请求index.html的时候,服务器不仅返回index.html的内容,同时将index.css和index.js的内容push给浏览器,当浏览器下次请求这2两个文件时就可以直接从缓存中读取了。
要想了解server push原理,首先要理解一些概念。我们知道HTTP2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧主要分成这几种类型:
Note:HTTP2.0相关的帧其实包括 10种帧 ,正是因为底层数据格式的改变,才为HTTP2.0带来许多的特性,帧的引入不仅有利于压缩数据,也有利于数据的安全性和可靠传输性。
下图表示了整个流程:
既然server push这么神奇,那么我们如何使用呢?怎么设置服务器push哪些文件呢?
首先并不是所有的服务器都支持server push,nginx目前还不支持这个特性,可以在nginx的官方博客上得到证实 https://www.nginx.com/blog/http2-r7/ ,但是Apache和nodejs都已经支持了server push这一个特性,需要说明一点的是server push这个特性是基于浏览器和服务器的,所以浏览器并没有提供相应的js api来让用户直接操作和控制push的内容,所以只能是通过header信息和server的配置来实现具体的push内容,本文主要以nodejs来说明具体如何使用server push这一特性。
准备工作:下载 nodejs http2 支持,本地启动nodejs服务。
var http2 = require('http2'); var url=require('url'); var fs=require('fs'); var mine=require('./mine').types; var path=require('path'); var server = http2.createServer({ key: fs.readFileSync('./zs/localhost.key'), cert: fs.readFileSync('./zs/localhost.crt') }, function(request, response) { var pathname = url.parse(request.url).pathname; var realPath = path.join("my", pathname); //这里设置自己的文件名称; var pushArray = []; var ext = path.extname(realPath); ext = ext ? ext.slice(1) : 'unknown'; var contentType = mine[ext] || "text/plain"; if (fs.existsSync(realPath)) { response.writeHead(200, { 'Content-Type': contentType }); response.write(fs.readFileSync(realPath,'binary')); } else { response.writeHead(404, { 'Content-Type': 'text/plain' }); response.write("This request URL " + pathname + " was not found on this server."); response.end(); } }); server.listen(443, function() { console.log('listen on 443'); });
这几行代码就是简单搭建一个nodejs http2服务,打开chrome,我们可以看到所有请求都走了http2,同时也可以验证多路复用的特性。
2. 设置我们的server push:
var pushItem = response.push('/css/bootstrap.min.css', { request: { accept: '*//*' }, response: { 'content-type': 'text/css' } }); pushItem.end(fs.readFileSync('/css/bootstrap.min.css','binary'));
我们设置了bootstrap.min.css来通过server push到我们的浏览器,我们可以在浏览器中查看:
可以看到,启动server push的资源timelime非常快,大大加速了css的获取时间。
try { pushItem.end(fs.readFileSync('my/css/bootstrap.min.css','binary')); } catch(e) { response.writeHead(404, { 'Content-Type': 'text/plain' }); response.end('request error'); } pushItem.stream.on('error', function(err){ response.end(err.message); }); pushItem.stream.on('finish', function(err){ console.log('finish'); });
上面的代码你可能会发现许多和正常nodejs的httpserver不一样的东西,那就是stream,其实整个http2都是以stream为单位,这里的stream其实可以理解成一个请求,更多的api可以参考: node-http2 。
参考资料: