前言:
最近在做基于 node-express 的个人站点 朵朵视野 ,在站点发布之后自己在访问测试的过程中发现站点是没有缓存机制的,这样就导致每次访问站点都需要重新去加载资源,很消耗资源以及用户体验也不是很好.
因为站点有上述问题,所以就着手去解决这个问题,解决方法就是通过浏览器缓存来实现。解决过程也是一波三折,最开始想的是通过设置最大过期时间 maxage 来实现,但是做完测试过程中发现通过这种方法添加浏览器缓存之后,当服务重启之后浏览器缓存依旧存在,而且必须通过手动清空缓存才可以使文件更改的内容生效。
设置过期时间 maxage 无法解决问题就只能继续找解决方法,通过了解浏览器缓存机制发现了第二种方法,就是通过 Last-Modified 实现,现将具体的实现过程记录如下。
node-express通过脚手架生成的项目目录结构如下:
bin下的www是项目入口
node_moduls 项目所需模块
public 静态资源,如图片,js,css
routes 路由文件
views 页面文件
app.js 项目需要的中间件等基本配置
package.json 定义项目的基本信息等,包括项目所需要的模块名和版本号
通过设置 maxage 实现浏览器缓存
1 app.use(express.static(myStaticPath, { 2 maxage: '2h' 3 }))
通过 express.static() 来设置浏览器缓存仅仅只是设置了过期时间,不能够保证服务重启之后浏览器缓存失效,实际项目中发现服务重启之后必须要手动清空浏览器缓存之后才能够将更改的文件正确显示,用户体验不好。
通过设置 Last-Modified 实现浏览器缓存
Last-Modified 实现浏览器缓存原理:浏览器第一次向服务端发送请求时,服务端会返回一个带有 Last-Modified: Sat, 02 Dec 2019 09:03:12 GMT 字段的响应头,表明所请求的文件最新修改时间;当浏览器下一次向服务端发送请求时,请求头会带上 If-Modified-Since: Sat, 02 Dec 2019 09:03:18 GMT字段,该字段的值是上一次服务器 Last-Modified 返回的值,服务器接收到请求后会根据 If-Modified-Since 值进行判断,如果该值小于服务器文件的值则返回新的文件,否则就告诉浏览器使用缓存文件。
node-express 生成的代码结构中创建服务的代码被集合在 app.js 中,这样的话我们设置 Last-Modified 就需要在 app.js 中设置。app.js 中有一段处理 404 错误的代码段,我们可以把设置 Last-Modified 集合到这段代码中。
未添加 Last-Modified 代码的 404 错误处理代码段如下:
1 app.use(function (req, res. next) { 2 var err = new Error('Not Found'); 3 err.status = 404; 4 next(err); 5 })
添加 Last-Modified 处理的 404 错误处理代码段如下:
1 app.use(function (req, res. next) { 2 var pathname = url.parse(req.url).pathname ; 3 // 获取文件日期 4 fs.stat('.' + pathname, (err, stat) => { 5 if(err) { 6 var err = new Error('Not Found'); 7 err.status = 404; 8 next(err); 9 }else { 10 if (req.headers['if-modified-since']) { 11 // 浏览器 if-modified-since 字段值 12 var oDate = new Date(req.headers['if-modified-since']); 13 var time_client = Math.floor(oDate.getTime() / 1000); 14 // 服务端文件最新修改时间 15 var time_server = Math.floor(stat.mtime.getTime() / 1000); 16 if (time_client < time_server) { 17 // 浏览器缓存文件的修改时间小于服务端文件修改时间,发送文件 18 sendFileToClient(); 19 }else { 20 // 浏览器缓存文件的修改时间等于或大于服务器文件的修改时间 21 // 发送 304 状态码,告知浏览器从缓存中读取数据 22 res.writeHeader(304); 23 res.write('Not Modified'); 24 res.end(); 25 } 26 }else { 27 // 浏览器是第一次请求该文件,不存在 if-modified-since 字段 28 // 从服务器端读取文件 29 sendFileToClient(); 30 } 31 function sendFileToClient() { 32 var rs = fs.createReadStream(`.${pathname}`); 33 // 设置请求头 Last-Modified 字段,值为该文件最新修改时间 34 res.setHeader('Last-Modified', stat.mtime.toGMTString()); 35 // 输出 36 rs.pipe(res); 37 rs.on('error', err => { 38 var err = new Error('Not Found'); 39 err.status = 404; 40 next(err); 41 }); 42 } 43 } 44 }) 45 })
后话:
通过设置 Last-Modified 根本上解决了浏览器缓存文件更改后无法感知更新的问题,无论是访问速度还是用户体验上都有了很大的提高。