最近在复习浏览器缓存,在复习过程中产生了很多的疑问,决定来实际使用一下测试真实情况。理论知识参考的 (1.6w字)浏览器灵魂之问,请问你能接得住几个? 这篇文章。
强缓存
- Expires
- Cache-Control
Expires
首先测试下 Expires,首先使用 Express 搭建一个本地服务器。使用 static 访问本地的 public 文件夹,通过配置 etag, cacheControl, lastModified 为 false,禁用所有的缓存。
const express = require('express')
const app = express()
const port = 3000
app.get('/hello', (req, res) => res.send('Hello World!'))
app.use('/static', express.static('public', {
etag: false,
cacheControl: false,
lastModified: false,
}))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
启动起来后可以在本地访问多次看下状态都是 200,没有缓存,Response Headers 里面没有缓存相关的字段。
然后我们添加上 Expires 字段测试一下。我们给所有请求的 Header 加上 Expires 字段,设置过期时间为请求后的 60 秒后。
app.use('/static', express.static('public', {
etag: false,
cacheControl: false,
lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
}
}))
可以看到第一次请求 index.html 和 test.js 的 Response Headers 里面都有 Expires 字段,时间为发起请求 + 60 秒。
然后我们再次刷新,可以看到 test.js 直接从 memory cache 里面取的,看下后端的日志,也没有打印出来 /static/test.js 的请求 url,说明 Expires 生效了,但是对于 index.html 确没有生效,这里没有搞清楚原因,希望知道的指点一下。 60 秒后再次刷新,可以看到又是从后端后去资源了。
另外,Expires 是跟本地时间有关系的,我们也可以测试下。因为不好截图显示我修改了本地时间,在此就不截图了,具体操作是:先请求,然后修改本地时间到一分钟后,刷新,可以看到并没有缓存。
Cache-Control
然后测试 Cache-Control,文档里说到 Cache-Control 和 Expires 同时存在时,优先考虑 Cache-Control,所以我们直接加上 Cache-Control 字段测试一下。
app.use('/static', express.static('public', {
etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
}
}))
继续刷新看结果,可以看到 Cache-Control 和 Expires 同时存在,但是 Expires 不生效了,每次都是 200 并且没有取缓存。
因为没有设置 max-age,Cache-Control 的默认值为 public, max-age=0,所以没有缓存效果,现在设置下 max-age 为 10 秒。
app.use('/static', express.static('public', {
etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
// 这里的 maxAge 是毫秒,但是 Response Header 中的 max-age 是秒单位
maxAge: 10000,
lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
}
}))
刷新看结果,10 秒内直接取缓存。
然后测试下 Cache-Control 的其他设置值。
- no-cache 跳过强缓存,直接进入协商缓存
app.use('/static', express.static('public', {
etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
// 这里的 maxAge 是毫秒,但是 Response Header 中的 max-age 是秒单位
maxAge: 10000,
lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
res.append('Cache-Control', 'no-cache');
}
}))
刷新可以看没有强缓存,无 memory cache
- no-store 不进行任何缓存
app.use('/static', express.static('public', {
etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
// 这里的 maxAge 是毫秒,但是 Response Header 中的 max-age 是秒单位
maxAge: 10000,
lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
res.append('Cache-Control', 'no-store');
}
}))
刷新可以看没有强缓存,无 memory cache
- private/s-maxage 这两个字段用于代理服务器,没搞明白如何测试代理服务器,求助大家。
协商缓存
当强缓存失效后,会根据是否存在协商缓存字段进行协商缓存阶段
- Last-Modified
- ETag
Last-Modified
默认 lastModified 为 true,lastModified 设置为 true 时,会在 Response Headers 中添加 Last-Modified 字段,然后在下次请求该资源时把该字段放入 If-Modified-Since 中,服务器会根据资源的最近修改时间和 If-Modified-Since 进行对比,如果发现文件更新了,则返回 200,把最新更新时间放入 Last-Modified 中,如果没有更新,则返回 304,告诉浏览器直接用缓存。
app.use('/static', express.static('public', {
etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
// 这里的 maxAge 是毫秒,但是 Response Header 中的 max-age 是秒单位
maxAge: 10000,
// lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
res.append('Cache-Control', 'no-cache');
}
}))
第一次请求后再次直接请求 ,可以看到 index.html 和 test.js 都返回了 304,当我修改了 test.js 并保存后,可以看到 test.js 请求返回了 200。
可以看到返回了 Last-Modified 为最新的修改时间,比 If-Modified-Since 时间晚。
文章里说到 Last-Modified 能够感知的单位时间是秒,如果文件在 1 秒内改变了多次,那么这时候的 Last-Modified 并没有体现出修改了。这里我测试了一下确实是这样的。 我写了个 js 去修改 index.html
const fs = require('fs');
const res = fs.readFileSync('./public/index.html');
function sleep(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, time)
})
}
(async function() {
await sleep(10000);
for (let i = 0; i < 60; i++) {
await sleep(10);
fs.writeFileSync('./public/index.html', `${res} ${i}`);
}
})()
在 600 ms 内每 10 ms 去修改一次 index.html,可以看到最后获取到的 index.html里面的数字是 43,而实际上我的文件里内容是 59.
E-Tag
打开静态文件的 E-Tag 只需要去掉 etag: false,默认 etag 为 true
app.use('/static', express.static('public', {
// etag: false,
// 去掉 cacheControl 的 false 设置
// cacheControl: false,
// 这里的 maxAge 是毫秒,但是 Response Header 中的 max-age 是秒单位
// maxAge: 10000,
// lastModified: false,
setHeaders: function (res, path, stat) {
res.append('Expires', new Date(new Date().getTime() + 60 * 1000));
res.append('Cache-Control', 'no-cache');
}
}))
可以看到设置了 etag 之后就不会有 “Last-Modified 能够感知的单位时间是秒” 的问题了。每次文件有修改都会更新到 ETag
总结
到这里文章就结束了,总结一下:
- Cache-Control 的 max-age 和 Expires 控制强缓存,有 Cache-Control,则 Expires 失效。
- 强缓存失效,Last-Modified 和 ETag 控制协商缓存。ETag 优先级比 Last-Modified 优先级高。
- 另外需要注意,因为我使用的 express.static 支持缓存,如果是 Get 或者 Head 请求,可以自己实现或者使用中间件实现缓存效果。
另外有几个问题没有解决。
1.index.html 不会从 memory-cache 取,我猜测可能是浏览器认为是入口页面不会 memory-cache,而 index.html 里面引入的 test.js 则可以 memory-cache。
2.private 和 s-maxage 没有进行测试。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!