关于Cache-Control的特性
可缓存性
- 代表http请求返回的内容所经过的任何路径中, 包括中间的http代理服务器, 以及发出请求的客户端浏览器
- 都可以对返回内容进行缓存的操作,也就是把这份数据存在本地,下一次可以直接读取而非重新获取
- 网络中有很多代理服务器和发起的客户端都可以进行缓存的操作,它的可缓存性就是指那些地方可以执行缓存操作
- public:表示任何地方都可以进行缓存
- private:表示发起请求的浏览器才可以进行缓存
- no-cache:不表示不缓存,实际上,在每次请求中使用任何缓存响应之前,都要使用服务器重新验证。
到期
max-age=<seconds>
- 表示设置缓存的到期时间,用秒表示
- 过期后浏览器重新发起请求到服务器获取内容
s-maxage=<seconds>
- s-maxage可代替max-age
- 两个都设置了,在浏览器中用max-age,在代理服务器中用s-maxage
- 该项只有在代理服务器里面才会生效
max-stale=<seconds>
- 在max-age过期之后,如果返回的资源里存在max-stale设置
- 即使max-age过期了,如果在max-stale时间内仍然可以使用过期的缓存,而不用去重新请求
- max-stale在浏览器中用不到,浏览器在发起请求和静态资源请求中不会主动设置这个头
- max-stale是发起请求的一方主动带的一个头,只有在发起端设置是有用的,在服务端返回中设置是没用的
重新验证
must-revalidate
- 在设置的max-age缓存中已经过期了,必须去原服务端重新发起请求获取数据,来验证是否已经真的过期
- 而不能直接使用本地缓存
proxy-revalidate
- 用于缓存服务器中, 过期的时候必须去原服务器上请求最新内容,不能再使用本地缓存
- 以上两个基本不会怎么用到
其他
no-store
- 严格的本地和代理服务器都不可以存储缓存
- 永远用的都是新的
no-transform
- 用在代理服务器中,有些代理服务器会压缩和格式转换资源
- 此设置告诉代理服务器不要改动资源
重要的原则
- 以上头的设置都是原则性的,是一种规范,但是很多代理服务器可以完全不按着这个规范来做
- Nginx做代理是可以配置缓存的,它的权重会更高
浏览器从本地读取缓存示例
-
test.html
<script src="/script.js"></script>
-
server.js
const http = require('http'); const fs = require('fs'); http.createServer((req, res) => { console.log('req come: ', req.url); if(req.url === '/') { const html = fs.readFileSync('test.html', 'utf8'); // 默认是下面这个writeHead设置,不写也可以 res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(html); } if(req.url === '/script.js') { // 默认是下面这个writeHead设置,不写也可以 res.writeHead(200, { 'Content-Type': 'text/javascript' }); res.end("alert('script loaded')"); } }).listen(8000, () => { console.log('server is running on port 8000'); });
-
启动程序:$
node server.js
-
访问:http://localhost:8000/
-
弹出信息:script loaded
-
检查浏览器Network, 查找script.js项
- 显示 Status: 200 OK
- Size: 199B transferred from network, resource size: 22B
- Time: 3ms
-
修改程序,针对script.js的访问设置Cache-Control如下所示
res.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=20' // 设置缓存时间为20s });
-
重启服务:$
node server.js
-
访问:http://localhost:8000/
-
再次检查Network, Disable cache 保持未勾选状态
-
刷新浏览器,检查浏览器Network, 查找script.js项
- 显示 Status: 200 OK
- Size: memory cache, Served from network, resource size: 22B
- Time: 0ms
-
可见第二次访问script.js时,浏览器从缓存中读取了,这就是Cache
-
我们再次修改程序,针对script.js的返回,设置
res.end("alert('script loaded!!!')");
-
重启服务,$
node server.js
-
再次访问:http://localhost:8000/
-
弹出信息仍是:script loaded,没有新增的"!!!"
-
经过20s后, 再次刷新页面
-
弹出信息:script loaded!!!
-
可见Cache-Control是客户端缓存, 与服务端无关
-
服务端修改了js程序, 客户端访问的url仍是script.js, 没有发生变化
-
因此,客户端仍在有效期内使用缓存资源
-
这样,又会导致一个新的问题, 客户端无法及时的获取更细,如何解决呢?
- 我们希望浏览器能缓存js,css,img等资源文件加快页面速度,同时,也希望浏览器能够及时更新最新的程序
- 一般情况下,我们服务端设置的Cache-Control不需要变化, 可以设置一个较长时间的max-age
- 常见的前端解决方式是在构建流程时,会根据js内容的变化进行哈希计算,在打包后的js文件名上添加一串最新的哈希码
- 如果内容不变,哈希码不变,反应在web页面上就是请求js的资源地址也就不变,就不会请求最新的文件,仍使用客户端缓存文件
- 如果内容变化,哈希码变化,请求js的资源的路径发生变化,此时就会自动请求最新的资源,不会再使用缓存资源
-
另外,关于Cache-Control的设置,还可以在后面添加更多内容
- 如:
'Cache-Control': 'max-age=20, public'
- 不同的值会产生不同的效果, 用逗号分开即可
- 如:
-
在代理服务器上,Nginx也可以配置一些代理的Cache-Control的头,此处不再赘述