浏览器缓存详解_cache-control no-cache_我只有两毛钱的博客-CSDN博客 (建议收藏)为什么第二次打开页面快?五步吃透前端缓存,让页面飞起 - 掘金 (juejin.cn)
浏览器缓存的存储位置
localStorage
LocalStorage 的 API 打破了 cookie 只能在同一个域名下保存 4KB 数据的限制,所以 LocalStorage 可以存储更多的数据,而且在不同域名下的数据也是互相独立的。
LocalStorage 存储在客户端的本地硬盘上,而不是服务器上。每个域名下都会有独立的数据存储目录。LocalStorage 的数据存在硬盘上,所以和 cookie 不同,如果客户端清除了缓存,那么 LocalStorage 中的数据也会被清除。
sessionStorage
sessionStorage的数据缓存是保存在网页窗口的进程内存或线程内存中的,当网页窗口关闭的时候sessionStorage的数据缓存也自动清除了
面试官:你确定多窗口之间sessionStorage不能共享状态吗???🤔 - 掘金 (juejin.cn)
多窗口之间sessionStorage不可以共享状态,但是在某些特定场景下新开的页面会复制之前页面的sessionStorage。
按缓存位置分类
我们可以在 Chrome 的开发者工具中,Network -> Size 一列看到一个请求最终的处理方式:如果是大小 (多少 K, 多少 M 等) 就表示是网络请求,否则会列出 from memory cache, from disk cache 和 from ServiceWorker。
它们的优先级是:(由上到下寻找,找到即返回;找不到则继续)
- Service Worker,需要自己写代码开启
- Memory Cache,页面关闭就会被清除
- Disk Cache,强缓存与协商缓存的存储位置就是Disk Cache
- 网络请求
Memory Cache
Memory Cache 翻译过来便是“内存缓存”,顾名思义,它是存储在浏览器内存中的。其优点为获取速度快、优先级高,从内存中获取资源耗时为 0 ms,而其缺点也显而易见,比如生命周期短,当网页关闭后内存就会释放,同时虽然内存非常高效,但它也受限制于计算机内存的大小,是有限的。
那么如果要存储大量的资源,这是还得用到磁盘缓存。
Disk Cache
Disk Cache 翻译过来是“磁盘缓存”的意思,它是存储在计算机硬盘中的一种缓存,它的优缺点与 Memory Cache 正好相反,比如优点是生命周期长,不触发删除操作则一直存在,而缺点则是获取资源的速度相对内存缓存较慢。
Disk Cache 会根据保存下来的资源的 HTTP 首部字段来判断它们是否需要重新请求,如果重新请求那便是强缓存的失效流程,否则便是生效流程。
按失效策略分类
memory cache 是浏览器为了加快读取缓存速度而进行的自身的优化行为,不受开发者控制,也不受 HTTP 协议头的约束,算是一个黑盒。
Service Worker 是由开发者编写的额外的脚本,且缓存位置独立,出现也较晚,使用还不算太广泛。所以我们平时最为熟悉的其实是 disk cache,也叫 HTTP cache (因为不像 memory cache,它遵守 HTTP 协议头中的字段)。平时所说的强制缓存,对比缓存,以及 Cache-Control 等,也都归于此类。
强制缓存 (也叫强缓存)
强制缓存的含义是,当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。
强制缓存直接减少请求数,是提升最大的缓存策略。 它的优化覆盖了文章开头提到过的请求数据的全部三个步骤。如果考虑使用缓存来优化网页性能的话,强制缓存应该是首先被考虑的。
可以造成强制缓存的字段是 Cache-control 和 Expires。
Expires 使用的 GMT 格式的时间戳字符串,表示缓存过期的时间点。Cache-Control是通用头字段,请求头和响应头都可以使用。
Cache-Control请求头常见属性
| 字段(单位秒) | 说明 |
|---|---|
| max-age=300 | 拒绝接受长于300秒的资源,为0时表示获取最新资源 |
| max-stale=100 | 缓存过期之后的100秒内,依然拿来用 |
| min-fresh=50 | 缓存到期时间还剩余50秒开始,就不给拿了,不新鲜了 |
| no-cache | 协商缓存验证 |
| no-store | 不使用缓存 |
| only-if-chached | 只使用缓存,没有就报504错误 |
| no-transform | 不得对资源进行转换或转变。Content-Encoding, Content-Range, Content-Type等HTTP头不能由代理修改。然并卵 |
多少秒是自定义的,我这里写死是方便理解
no-cache 从语义上表示下次请求不要直接使用缓存而需要比对,并不对本次请求进行限制。因此浏览器在处理当前页面时,可以放心使用缓存。
Cache-Control响应头常见属性
| 字段(单位秒) | 说明 |
|---|---|
| max-age=300 | 缓存有效期300秒 |
| s-maxage=500 | 有效期500秒,优先级高于max-age,适用于共享缓存(如CDN) |
| public | 可以被任何终端缓存,包括代理服务器、CDN等 |
| private | 只能被用户的浏览器终端缓存(私有缓存) |
| no-cache | 先和服务端确认资源是否发生变化,没有就使用 |
| no-store | 不缓存 |
| no-transform | 与上面请求指令中的一样 |
| must-revalidate | 客户端缓存过期了就向源服务器验证 |
| proxy-revalidate | 代理缓存过期了就去源服务器重新获取 |
对比缓存 (也叫协商缓存)
当强制缓存失效(超过规定时间)时,就需要使用对比缓存,由服务器决定缓存内容是否失效。
流程上说,浏览器先请求缓存数据库,返回一个缓存标识。之后浏览器拿这个标识和服务器通讯。如果缓存未失效,则返回 HTTP 状态码 304 表示继续使用,于是客户端继续使用缓存;如果失效,则返回新的数据和缓存规则,浏览器响应数据后,再把规则写入到缓存数据库。
Last-Modified 和 If-Modified-Since
响应头字段 Last-Modified 表示提供的资源最后被修改的时间。值是 GMT 格式的字符串。
Last-Modified: Sat, 09 Apr 2022 14:47:36 GMT
这个时间会标记在对应缓存上,起到标识的作用。
当浏览器的缓存失效后,会再次请求服务端,并带上 If-Modified-Since 请求头字段,它的值就是之前 Last-Modified 带过来的值。
If-Modified-Since: Sat, 09 Apr 2022 14:47:36 GMT
当服务端发现资源最后修改时间和 If-modified-since 值相等,代表资源从该时间后再未改变过。
服务端于是返回 304(Not Modified)状态码,表示资源没有改变,并且响应体为空。浏览器拿到后,就知道原本可能过期的缓存其实还可以继续使用。
如果资源改变了,就会返回 200,且响应体带上最新资源。
ETag 和 If-None-Match
除了用 Last-Modified 代表的资源最后修改时间作为标识,我们还可以使用 ETag 响应头。
ETag 的值没有规定,你可以是时间戳的哈希值,也可以是版本号。
另外 ETag 分为强 ETag 和弱 ETag,其中弱 ETag 以为 W/ 开头。
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
然后和 If-Modified-Since 一样,当缓存过期时,客户端会在请求头带上 If-None-Match 去请求资源。
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
如果资源依旧新鲜,则返回 304,客户端继续复用本地资源。