一、介绍
http缓存:浏览器根据当前http请求报文策略 将网路资源存储到本地内存(memory cache)/硬盘(disk cache)中
缓存流程:
二、访问缓存优先级
三、分类
优先进行强缓存,强缓存失效后,进行协商缓存
不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size显示from disk cache或from memory cache。强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control
Expires: Sun, 26 Apr 2020 18:00:00 GMT 最大过期时间 2020/04/26 18:00:00
Expires:缓存过期时间,如果请求资源在到期时间内,直接从缓存里读取。因为是绝对时间,受限于本地时间,如果修改本地时间,可能会导致缓存失效
Cache-Control:max-age=300
Cache-Control:max-age=300 代表当前请求返回时间的5分钟之后,再次请求,直接从缓存里读取。默认值 private:
Cache-Control 指令有很多,并且可以组合使用:
指令 | 作用 |
---|---|
public | 所有内容都将被缓存(客户端和代理服务器都可缓存) |
private | 所有内容只有客户端可以缓存 |
no-cache | 不使用强缓存,使用协商缓存 |
no-store | 所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存 |
max-age | 表示缓存将在多少秒后失效 |
s-maxage | 同max-age作用一样,只在代理服务器中生效,s-maxage的优先级高于max-age |
… | … |
接下来我们测试一下强缓存:
这里把勾去掉,否则不会使用缓存
serve.js
let express = require('express')
let app = express()
let fs = require('fs')
let router = express.Router() // 这里使用Router
// 设置全局响应头
router.all('*', (req, res, next) => {
res.set({
'Cache-Control':'max-age=300' // 5分钟缓存时间
})
next()
})
// 静态资源
router.use(express.static('dist')) // 里面有index.html / 图片等静态资源
router.get('/userList', (req, res) => {
res.send({'name':'小明'})
})
app.use('/user',router) // 挂载
let server = app.listen(3000, '127.0.0.1', () => {
let host = server.address().address
let port = server.address().port
console.log('Server running at http://' + host + ':' + port)
})
接下来我们访问 127.0.0.1:3000/user/index.html
可以看到 强缓存已生效
接下来,我们F5刷新页面,此时进程还在,并且在缓存时间内,根据浏览器缓存原理,应该从 memory cache 中读取图片
我们可以看到 form memory cache 从内存中读取图片 !!!
接下来,我们把进程关掉,在缓存时间内,根据浏览器缓存原理,应该从 disk cache 硬盘中读取图片
看到 form disk cache 从硬盘中读取图片,完全符合访问缓存优先级
接下来,我们尝试 5 分钟之后,也就是请求缓存时间到期后,再次请求
我们可以看到,缓存时间到期后,直接从服务端发起请求
总结流程,在缓存时间内:
如果不设置 Cache-Control 默认public,max-age=0,当然我们可以设置为 Cache-Control : no-cache
serve.js
let express = require('express')
let app = express()
let fs = require('fs')
let router = express.Router() // 这里使用Router
// 设置全局响应头
router.all('*', (req, res, next) => {
res.set({
'Cache-Control':'no-cache' // 进行协商缓存
})
next()
})
// 静态资源
router.use(express.static('dist')) // 里面有index.html / 图片等静态资源
router.get('/userList', (req, res) => {
res.send({'name':'小明'})
})
app.use('/user',router) // 挂载
let server = app.listen(3000, '127.0.0.1', () => {
let host = server.address().address
let port = server.address().port
console.log('Server running at http://' + host + ':' + port)
})
接下来我们访问 127.0.0.1:3000/user/index.html
可以看到,Cache-Control : no-cache 已经生效
我们发现返回值多了ETag 和 Last-Modified
代表我们当前请求的数据在服务端的唯一标识,首次请求时,服务端会返回Etag标识,浏览器下次请求时,会带上赋值后的 If-None-Match 参数,并且与返回的ETag进行对比,如果一致则命中协商缓存。返回 304 Not Modified
代表请求的数据在服务端最后一次修改的时间,同理,首次请求时,服务端会返回Last-Modified标识,浏览器下次请求时,会带上赋值后的 If-Modified-Since 参数,并且与返回的Last-Modified进行对比,如果一致则命中协商缓存。返回 304 Not Modified
!!!注意:Etag 的优先级要高于 Last-Modified,所以请求时,如果ETag存在,则对比 If-None-Match,反之对比 If-Modified-Since
可以看到,Etag 与 If-None-Match 对比一致,命中协商缓存,返回 304 Not Modified
然后,我们修改服务端静态资源,再次请求
我们会看到浏览器保留的 If-None-Match 与 响应头 Etag 对比不一致,缓存策略失效!!!发送请求
总结协商缓存:
至此,我们就彻底搞懂http缓存机制