- 304
- 强制缓存
- Expires/Cache-Control
- no-cache
- 对比缓存
- Last-Modifed与if-modified-since
- Etag与if-none-match
- 两种缓存一起使用
- 浏览器行为
- Memory Cache 和 Disk Cache的区别
- f5和ctrl+f5
304
res.statusCode = 304;复制代码
当我们在响应信息中回复304时,浏览器会自动从本地的缓存数据库中拿取数据。
嗯,这句其实是缓存中最关键的一句,其它的获取设置缓存相关的头都是再为是否输出这一句话做铺垫。
强制缓存
Expires/Cache-Control
res.setHeader('Expires',date.toUTCString());res.setHeader('Cache-Control','max-age=10'); //以秒为单位复制代码
Expires
和Cache-Control
都能起到强制缓存的作用,即在一定时间内客户端的请求会先走本地缓存而不是向服务器发起。
其中Expires是http1.0
协议中的头,我们使用它一般都是为了兼容,值得注意的是Expires的值和Cache-Control的值是不一样的。
Expires的值要求必须是GMT格式(?嗯,印象中有人这么说过,反正我不用。。。),而Cache-Control值的格式则为max-age=xxx
,xxx是一个数字,是一个相对时间,单位为秒。
no-cache
当Cache-Control
置为no-cache
时,客户端每次请求都会先忽略本地缓存直接向服务端询问是否要采用缓存。
对比缓存
又称之为“协商缓存”
Last-Modifed与if-modified-since
根据文件的修改时间是否发生改变来决定是否采取缓存。
res.setHeader('Last-Modified',stat.ctime.toUTCSting());复制代码
let since = req.headers['if-modified-since'];if(since){ if(since === stat.ctime.toUTCString()){ //没有被修改 res.statusCode = 304; //让它去缓存中找 res.end(); }else{ sendFile(req,res,p,stat); }}else{ sendFile(req,res,p,stat);}复制代码
注意: 这个时间格式并没有强制的限制,但我们要注意在使用中要保持格式的一致。
Etag与if-none-match
根据文件的内容是否发生改变来决定是否采取缓存。
function sendFile(req,res,p,stat){ res.setHeader('Cache-Control','no-cache'); //不走本地缓存,会向服务器询问 res.setHeader('Etag',r); res.setHeader('Content-Type',mime.getType(p)+';charset=utf8'); ...}复制代码
...let md5 = crypto.createHash('md5');let rs = fs.createReadStream(p);rs.on('data',function(data){ md5.update(data);});rs.on('end',function(){ let r = md5.digest('hex'); //对当前文件进行摘要 let ifNoneMatch = req.headers['if-none-match']; if(ifNoneMatch){ if(ifNoneMatch===r){ res.statusCode = 304; res.end(); }else{ sendFile(req,res,p,r); } }else{ sendFile(req,res,p,r); }})...复制代码
如果文件过大时,进行摘要是很不实际的,So我们一般选择ctime+size作为Etag
的值。
两种缓存一起使用
一般来说会同时使用上以上两种缓存,这个时候会先看强制缓存是否过期,没有过期就会从本地缓存中拿数据,只有过期了才会向服务器询问,这样有利于减轻服务器的鸭梨。
浏览器行为
Memory Cache 和 Disk Cache的区别
Memory Cache 和 Disk Cache 是浏览器缓存的两种模式。
笔者也不是很了解,这里抛出只是为了完善体系,这里给出一些社区的回答
f5和ctrl+f5
f5:跳过强制缓存,但是会检查协商缓存
ctrl+f5:跳过强制缓存和协商缓存,服务器重新发送数据给浏览器