目标
- 了解缓存分类
- 能根据浏览器的响应结果, 判断当前是否命中了缓存, 以及是命中的哪类缓存
- 缓存导致的读取了旧内容问题, 如何解决
写在前面
- nginx默认就启用了缓存功能哈(强缓存和协商缓存都已默认启用), 只要直接部署好就可以了
- nginx的缓存时间/失效时间以及是否启用缓存都是可以配置的
- 不要光看, 部署一个简单的项目到nginx中试试, 然后观察每个资源的响应结果, 来加深理解和记忆
浏览器缓存的优点
- 减少重复数据请求,避免通过网络再次加载资源,节省流量
- 降低服务器压力,提升网站性能
- 加快客户端加载网页的速度,提升用户体验
浏览器读取资源粗略流程
- 浏览器在加载资源时,根据请求头的expires和cache-control来判断是否命中强缓存,是则直接从缓存中读取资源,不发送请求到服务器
- 如果没有命中强缓存,浏览器会发送请求至服务器,通过last-modified, etag, If-None-Match, If-Modified-Since 验证资源是否命中协商缓存,如果命中,服务器会将这个请求返回,但是不会返回这个资源的数据,依然是从缓存中读取数据
- 如果前面两者都没有命中,直接从服务器加载资源
缓存分类
缓存分为两类: 强缓存和协商缓存
强缓存: 如果资源在本地已存在,则浏览器直接使用本地的资源,完全不会再取服务器获取资源(哪怕实际的资源在服务器已经更新)
协商缓存: 在本地已存在该资源的请跨下,浏览器依然会去请求服务器,看当前缓存的资源是否依然是有效的,如果是有效的,则服务器返回304状态码(此时浏览器就会使用本地缓存),否则,使用服务器提供的最新版本的资源
缓存优先级
强缓存优先于协商缓存
如何判断某个请求是否有使用缓存
按缓存位置分类我们可以分为memory cache、disk cache、Service Worker三类,我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache、from disk cache、from Service Worker就表示命中了缓存。
1、memory cache 是内存中的缓存,(与之相对 disk cache 就是硬盘上的缓存)。按照操作系统的常理:先读内存,再读硬盘。
2、disk cache 也叫 HTTP cache,顾名思义是存储在硬盘上的缓存,因此它是持久存储的,是实际存在于文件系统中的。而且它允许相同的资源在跨会话,甚至跨站点的情况下使用,例如两个站点都使用了同一张图片。
3、上述的缓存策略以及缓存/读取/失效的动作都是由浏览器内部判断进行的,我们只能设置响应头的某些字段来告诉浏览器,而不能自己操作。
service work给予了我们另外一种更加灵活,可以直接的操作方式。我们可以从 Chrome 的 Application找到Service Workers。这个缓存是永久性的,即关闭 TAB 或者浏览器,下次打开依然还在(而 memory cache 不是)。
有两种情况会导致这个缓存中的资源被清除:手动调用 API cache.delete(resource) 或者容量超过限制,被浏览器全部清空。
如何判定命中的是哪类缓存
如何判断当前请求的资源,命中了协商缓存?
- 一旦资源被缓存且还没失效时,多次访问该资源,响应状态码都为
304
如何判断当前请求的资源,命中了强缓存?
- 响应状态为200 且
form xxx cache
用户行为对浏览器缓存的影响
所谓用户行为对浏览器缓存的影响,指的就是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种:
- 打开网页,地址栏输入地址: 查找 disk cache 中是否有匹配。如有则使用;如没有则发送网络请求;
- 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用 (如果匹配的话)。其次才是 disk cache;
- 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache), 服务器直接返回 200 和最新内容。
重要:用户在浏览器地址栏输入url或点击浏览器的刷新按钮, 或使用刷新的快捷键以及超链接在新标签页或新窗口中打开网址, 都会触发该网址资源的协商缓存 [想验证的话,直接用nginx部署一个vue项目,然后观察html资源的响应状态码即可]
对于浏览器已经强缓存的资源, 服务器实际已经将资源更新了,但浏览器依旧使用的缓存结果, 怎么破?
对打包的产出的文件, 文件名的命名规则, 改为: 原文件名-文件内容hash.文件后缀方式, 这样如果文件内容改变,文件名也会改变, 对于浏览器而言, 请求的就是不同的文件, 那么就不存在读取到缓存的旧内容问题了.
获取有的小伙伴会想:"你的静态的js,css,甚至图片文件都使用上面hash方式命名, 似乎能解决强缓存问题, 但你index.html页面, 总不能每次发版都改名字了吧, 如果index.html页面都读取的强缓存, 那你那些css和js啥的静态资源按文件内容进行hash命名也没意义呀"
能想到这点说明你确实在思考, 可注意看那段标了 重要 的内容, 想访问html内容, 通常是需要在浏览器输入地址或使用f5刷新的, 此时会触发协商缓存的判断, 所以在服务端没有配置错误的情况下, 不用担心此时会导致浏览器直接读取缓存.
nginx缓存配置示例
示例一
location / {
# 其它配置
...
if ($request_uri ~* .*[.](js|css|map|jpg|png|svg|ico)$) {
#非html缓存1个月
add_header Cache-Control "public, max-age=2592000";
}
if ($request_filename ~* ^.*[.](html|htm)$) {
#html文件使用协商缓存
add_header Cache-Control "public, no-cache";
}
}
示例二
location ~.*\.(js|css|html|png|jpg|gif)$ {
expires 3d;
}
expires 3d; //表示缓存3天
expires 3h; //表示缓存3小时
expires max; //表示缓存10年
expires -1; //表示永远过期。
如果设置为-1在js、css等静态文件在没有修改的情况下返回的是http 304,如果修改返回http 200
http 304:自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
http 200:服务器已成功处理了请求,这表示服务器提供了请求的内容。
如果不想让代理或浏览器缓存,加no-cache参数
add_header Cache-Control no-cache;
这样浏览器F5刷新时,返回的就是http 200,而不是http 304
示例三
location ^~ /demo/ {
root D:/demo;
add_header Cache-Control no-store;
}
禁止html资源的缓存
location / {
expires 1h;
root /home/html;
index index.html index.htm;
## html不缓存
if ($request_filename ~* .*\.(htm|html)$)
{
add_header Cache-Control "no-store";
}
}
nginx清除缓存
nginx缓存以及清除缓存_nginx清除缓存-CSDN博客
nginx缓存命中统计
Nginx 日志格式及缓存命中统计_nginx 请求量、响应时间、响应字节数、缓存情况 统计-CSDN博客
附录
开发常见响应状态码和意思
| Http状态码 | Http状态码含义中文说明 |
|---|---|
| 200 | 请求成功 |
| 301 | 永久重定向 |
| 302 | 临时重定向 |
| 304 | 请求资源与本地缓存相同,未修改 |
| 400 | 请求错误,通常是访问的域名未绑定引起 |
| 401 | 需要身份认证验证 |
| 403 | 禁止访问 |
| 404 | 资源不存在或已删除 |
| 405 | 请求方法不允许 |
| 408 | 请求超时 |
| 500 | 服务端程序错误 |
| 502 | 网关无响应 |
| 504 | 网关超时 |
| 599 | 网络连接超时 |
参考文章
如何在nginx上设置html不缓存 - 掘金 (juejin.cn)
Nginx配置强缓存和协商缓存 - 掘金 (juejin.cn)
查看缓存数据 - Microsoft Edge Development | Microsoft Learn
http面试必会的:强制缓存和协商缓存 - 掘金 (juejin.cn)
强缓存与协商缓存_java性能优化之强缓存与协商缓存-CSDN博客
nginx配置浏览器缓存(强缓存、协商缓存、无缓存)_nginx缓存-CSDN博客