前言:

  最近在做基于 node-express 的个人站点 朵朵视野 ,在站点发布之后自己在访问测试的过程中发现站点是没有缓存机制的,这样就导致每次访问站点都需要重新去加载资源,很消耗资源以及用户体验也不是很好.

  因为站点有上述问题,所以就着手去解决这个问题,解决方法就是通过浏览器缓存来实现。解决过程也是一波三折,最开始想的是通过设置最大过期时间 maxage 来实现,但是做完测试过程中发现通过这种方法添加浏览器缓存之后,当服务重启之后浏览器缓存依旧存在,而且必须通过手动清空缓存才可以使文件更改的内容生效。

  设置过期时间 maxage 无法解决问题就只能继续找解决方法,通过了解浏览器缓存机制发现了第二种方法,就是通过 Last-Modified 实现,现将具体的实现过程记录如下。

node-express通过脚手架生成的项目目录结构如下:

bin下的www是项目入口

node_moduls 项目所需模块

public 静态资源,如图片,js,css

routes 路由文件

views 页面文件

app.js 项目需要的中间件等基本配置

package.json 定义项目的基本信息等,包括项目所需要的模块名和版本号

通过设置 maxage 实现浏览器缓存

 app.use(express.static(myStaticPath, {
maxage: '2h'
}))

通过 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 错误处理代码段如下:

 app.use(function (req, res. next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
})

  添加 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 根本上解决了浏览器缓存文件更改后无法感知更新的问题,无论是访问速度还是用户体验上都有了很大的提高。

node-express脚手架生成的项目中实现浏览器缓存的更多相关文章

  1. Node + Express + vue2.0 + Webpack项目实践

    技术 Express.Vue.Vue-Router.Vue-Resource.Webpack Vue vue 的组件化思想和 React 很像,一个 vue 组件将 html.css 和 js 都写在 ...

  2. 【手摸手,带你搭建前后端分离商城系统】02 VUE-CLI 脚手架生成基本项目,axios配置请求、解决跨域问题

    [手摸手,带你搭建前后端分离商城系统]02 VUE-CLI 脚手架生成基本项目,axios配置请求.解决跨域问题. 回顾一下上一节我们学习到的内容.已经将一个 usm_admin 后台用户 表的基本增 ...

  3. vue-cli+webpack在生成的项目中使用bootstrap方法(二)

    vue-cli+webpack在生成的项目中使用bootstrap方法(一)中,是通过手动下载bootstrap库,然后手动添加到src/assets中,显然是过程太多. 当然是可以更省力些,可以通过 ...

  4. 全面解析vue-cli生成的项目中使用其他库(js库、css库)

    前言:最近有小伙伴问我,是不是用vue脚手架生成的项目就不能jquery了呢?显然,答案是否定的,必须能用.但是个人建议最好不要用了,用人家vue提供的不好嘛. 一.用vue-cli生成项目 1. v ...

  5. 解决Ajax中IE浏览器缓存问题

    解决Ajax中IE浏览器缓存问题 1.首先,先看一张图.从这张图中我们可以清楚的了解到从请求的发出到解析响应的过程. 2.根据图中的三个节点我们可以使用三种方式解决这个缓存问题(主要是针对ie) 2. ...

  6. vue-cli+webpack在生成的项目中使用bootstrap

    在也个html页面中加入bootstrap是很方便,就是一般的将css和js文件通过Link和Script标签就行. 那么在一个用vue-vli生成的前端项目中如何加入?因为框架不一样了,略微要适应一 ...

  7. vue-cli+webpack在生成的项目中使用bootstrap的方法

    在一个html页面中加入bootstrap是很方便,就是一般的将css和js文件通过Link和Script标签就行.那么在一个用vue-vli生成的前端项目中如何加入?因为框架不一样了,略微要适应一下 ...

  8. vue-cli+webpack在生成的项目中使用bootstrap方法(一)

    在一个html页面中加入bootstrap是很方便,就是一般的将css和js文件通过Link和Script标签就行. 那么在一个用vue-vli生成的前端项目中如何加入?因为框架不一样了,略微要适应一 ...

  9. nuxt 脚手架创建nuxt项目中不支持es6语法的解决方案

    node本身并不支持es6语法,我们通常在vue项目中使用es6语法,是因为,我们使用babel做过处理, 为了让项目支持es6语法,我们必须同时使用babel 去启动我们的程序,所以再启动程序中加 ...

随机推荐

  1. Redis面试热点工程架构篇之数据同步

    温馨提示 更佳阅读体验:[决战西二旗]|Redis面试热点之工程架构篇[2] 前言 前面用了3篇文章介绍了一些底层实现和工程架构相关的问题,鉴于Redis的热点问题还是比较多的,因此今天继续来看工程架 ...

  2. IUSEP研修报告

    目录 Introduction Alberta - Edmonton University of Alberta IUSEP Schoolwork and Project Principle of F ...

  3. QQ音乐接口api,包括付费音乐、无损音乐、高品质音乐地址解析接口api

    QQ音乐网站所有音乐(包括付费.无损等版权音乐解析接口地址url). mp3 普通高品 http://dl.stream.qqmusic.qq.com/M5000012gqVh4fFvVK.mp3?v ...

  4. CUDA架构及对应编译参数

    NVIDIA CUDA C++ 编译器 nvcc 基于每个内核,既可以用来产生特定于体系结构的 cubin 文件,又能产生前向兼容的 PTX 版本. 每个 cubin 文件针对特定的计算能力版本,并且 ...

  5. Vue ES6箭头函数使用总结

    Vue ES6箭头函数使用总结   by:授客 QQ:1033553122   箭头函数 ES6允许使用“箭头”(=>)定义函数: 函数不带参数 定义方法:函数名称 = () => 函数体 ...

  6. JS---案例:美女时钟

    案例:美女时钟 思路: 打开页面就有图片按每秒1张的顺序轮换,用到了日期对象,获取小时和秒. 封装到一个命名函数后,为了使页面打卡就有图片的轮换,先调用下f1,再设置setInterval <! ...

  7. Elasticsearch7.5.0源码编译

    环境及工具 JDK12 Gradle5.6.2 GIT 源码及预处理 到github将代码clone下来,可以根据自己的需求来获取版本,例如 git checkout v7.5.0 提前下载gradl ...

  8. 【.net core 入坑】.net core 3.0 报错:在 FETCH 语句中选项 NEXT 的用法无效

    目录 1.事故现场: 2.分析及解决方案: 1.事故现场: 在项目中使用.net core 3.0,在EF链接sqlserver2008,在程序中使用了分页用的skip和take,程序报错: 在 FE ...

  9. 【1】基于OpenCV的DLL动态库隐式连接

    1DLL的作用 DLL是一个包含可由多个程序同时使用的代码和数据的库.例如:在Windows操作系统中,Comdlg32 DLL执行与对话框有关的常见函数.因此,每个程序都可以使用该DLL中包含的功能 ...

  10. Jmeter常用的两大性能测试场景

    一.阶梯式场景 该场景主要应用在负载测试里面,通过设定一定的并发线程数,给定加压规则,遵循“缓起步,快结束”的原则,不断地增加并发用户来找到系统的性能瓶颈,进而有针对性的进行各方面的系统优化. 使用到 ...