HTTP缓存机制
HTTP的缓存机制分为两种,一种是强缓存一种是协商缓存。主要作用是加快资源的获取速度,提升用户体验,减少网络传输,缓解服务器端的压力。
强缓存:
不需要发送请求到服务器端,直接读取浏览器本地资源。在Chrome的network中显示的HTTP状态码是200,在Chrome中,强缓存又分为Disk Cache(存放在硬盘中)和Memory Cache (存放在内存中),存放的位置是浏览器控制的。是否强缓存由Expriess 、Cache-Control和pragma 3个header属性共同控制的。
○ Expires
expires的值是一个HTTP日期,在浏览器发起请求时,会根据系统时间和Expires的值进行比较,如果系统时间超过Expires的值,缓存失效。由于系统时间进行比较,所以当系统时间和服务的时间不一致的时候,会有缓存有效期不准确的问题。Expires的优先级在三个Header属性中是最低的。
○ Cache-Control
Cache-Control是HTTP/1.1 中新增的属性,在请求头和响应头中都可以使用,常见属性值有:
- max-age:单位是秒,缓存时间计算方式是距离发起的时间的秒数,超过间隔秒数缓存失效
- no-cahe:不使用强缓存,需要与服务器端验证缓存是否新鲜
- no-store:禁止使用缓存(包括协商缓存),每次都向服务器请求最新的资源。
- private:专用于个人缓存,中间代理,CDN等不能缓存此响应。
- must-revalidate: 在缓存过期前可以使用,过期后必须向服务器验证。
○ Pragma
Pragma 只有一个属性。就是no-cache,效果和cache-control中的no-cache一致,不使用强缓存,需要与服务器端来验证缓存是否新鲜,在3个头部属性中优先级最高。
const express = require('express');
const app = express();
var options = {
etag: false, // 禁用协商缓存
lastModified: false, // 禁用协商缓存
setHeaders: (res, path, stat) => {
res.set('Cache-Control', 'max-age=10'); // 强缓存超时时间为10秒
},
};
app.use(express.static((__dirname + '/public'), options));
app.listen(3000);
协商缓存
在浏览器的强缓存失效的时候或者请求头中设置了不走强缓存,并且在请求头中设置了If-Modified-Since或者If-None-Match 的时候,会将这两个属性值到服务端去验证是否命中协商缓存,如果命中了协商缓存,会返回304,加载浏览器缓存,并且响应头会设置Last-Modified或者Etag属性。
○ ETag/If-None-Match
ETag/If-None-Match的值是一串hash吗,代表的是一个资源的标识符,当服务器的文件变化时,它的hash码就会随之改变,通过请求头的If-None-Match和当前文件的hash值进行比较,如果相等则表示命中协商缓存。ETag又有强弱校验之分,如果hash码是以‘W/’开头的一串字符串,说明此时的协商缓存是弱校验,只有服务器上的文件差异达到能够触发hash值后缀变化的时候,才会真正的请求支援,否则返回304并加载浏览器缓存。
○ Last-Modified/If-Modified-Since
Last-Modified/If-Modified-Since的值代表的是文件最后修改的时间,第一次请求服务器会把资源的最后修改时间放到Last-Modified响应中,第二次发起请求的时候,请求头会带上上一次响应头中的Last-Modifid的时间,并放到If-Modified-Since 请求头属性中,服务器端根据文件最后一次的修改时间个If-Modified的值进行比较,如果相等,则返回304,并加载浏览器缓存。
const express = require('express');
const app = express();
var options = {
etag: true, // 开启协商缓存
lastModified: true, // 开启协商缓存
setHeaders: (res, path, stat) => {
res.set({
'Cache-Control': 'max-age=00', // 浏览器不走强缓存
'Pragma': 'no-cache', // 浏览器不走强缓存
});
},
};
app.use(express.static((__dirname + '/public'), options));
app.listen(3001);