除了强缓存、协商缓存,你还知道启发式缓存吗?

除了强缓存、协商缓存,你还知道启发式缓存吗?

  大家多多少少对浏览器的强缓存 和协商缓存 都有一定的了解。但是不知道大家有没有遇到过这种情况,就是服务器的响应头里没有配置 Expires 和 cache-control。而是配置了 Last-Modified 和 ETag。理论上这种情况下浏览器应该要走协商缓存,但是结果却返回的 200(from memory cache),直接走的强缓存。为什么会出现这种情况呢?

  那是因为还有一种被称为启发式缓存的机制,它在某些情况下会自动生效。首先简单过一遍强缓存和协商缓存的概念。

强缓存

  强缓存是指浏览器在请求资源时,直接从本地缓存中获取资源,而不需要向服务器发送请求。强缓存的有效性由响应头中的 Cache-Control 和 Expires 字段控制。

  • Cache-Control: 该字段用于指定资源的缓存策略。常见的值如下表所示:

    值 描述 示例
    max-age=<seconds> 指定资源的最大缓存时间,单位为秒 Cache-Control: max-age=3600 表示资源可以在客户端缓存 1 小时
    no-cache 强制客户端在使用缓存前,先向服务器验证资源是否有效 Cache-Control: no-cache 表示每次请求都必须向服务器验证资源是否有效
    no-store 禁止缓存资源,每次请求都必须从服务器获取最新资源 Cache-Control: no-store 表示资源不能被缓存
    public 表示资源可以被任何缓存(如代理服务器)缓存 Cache-Control: public, max-age=3600 表示资源可以被任何缓存缓存 1 小时
    private 表示资源只能被客户端缓存,代理服务器不能缓存 Cache-Control: private, max-age=3600 表示资源只能被客户端缓存 1 小时
  • Expires : 该字段指定资源的过期时间,是一个绝对时间点。如果当前时间早于 Expires 指定的时间,则浏览器会使用缓存中的资源。例如,Expires: Thu, 20 Mar 2025 11:18:00 GMT 表示资源在 2025 年 3 月 20 日 11:18:00 GMT 之前有效。

  如果 Cache-Control 和 Expires 同时存在,Cache-Control 的优先级更高。

协商缓存

  当强缓存失效时 ,浏览器会向服务器发送请求,服务器会根据请求头中的 If-Modified-Since 或 If-None-Match 字段判断资源是否发生了变化。如果资源没有变化,服务器会返回 304 Not Modified 状态码,浏览器会继续使用缓存中的资源;如果资源发生了变化,服务器会返回新的资源。

  • Last-Modified / If-Modified-Since : Last-Modified 是服务器返回的响应头,表示资源的最后修改时间 。当浏览器再次请求该资源时,会在请求头中带上 If-Modified-Since 字段,值为上一次请求时服务器返回的 Last-Modified 值。服务器通过比较资源的最后修改时间和 If-Modified-Since 的值来判断资源是否发生了变化。例如,服务器返回 Last-Modified: Thu, 20 Mar 2025 11:18:00 GMT,浏览器再次请求时会在请求头中带上 If-Modified-Since: Thu, 20 Mar 2025 11:18:00 GMT。

  • ETag / If-None-Match : ETag 是服务器返回的响应头,表示资源的唯一标识符 。当浏览器再次请求该资源时,会在请求头中带上 If-None-Match 字段,值为上一次请求时服务器返回的 ETag 值。服务器通过比较资源的 ETag 和 If-None-Match 的值来判断资源是否发生了变化。例如,服务器返回 ETag: "5sd564sd5s665hg587s1a32wer5",浏览器再次请求时会在请求头中带上 If-None-Match: "5sd564sd5s665hg587s1a32wer5"。

  如果 Last-Modified 和 ETag 同时存在,ETag 的优先级更高。

启发式缓存

  启发式缓存是浏览器在没有明确的缓存指令 (如 Cache-Control 或 Expires)时,根据资源的 Last-Modified 时间自动推断出的缓存策略 。浏览器会根据资源的 Last-Modified 时间和Date的差值,推断出一个合理的缓存时间。

  以上图为例,资源的 Last-Modified 时间是 Wed, 19 Mar 2025 06:20:20 GMT,当前时间 Date是 Thu, 20 Mar 2025 02:14:54 GMT。客户端存储此响应(尽管缺少 max-age)并重用它一段时间。复用多长时间取决于实现,但规范建议存储后大约 10% 的时间,本例中就是 2 小时。

  但如果客户端的 Date 头比资源 Last-Modified 头早时:浏览器会认为资源已经过期,并重新请求资源。这种情况可能就是服务器时钟滞后或者人为错误修改了响应头。

  • 不会触发启发式缓存计算
  • 下次请求时直接发送完整请求(不带If-Modified-Since)
  • 开发者工具Console会显示时间异常警告

小结

  从缓存优先级上来看,显示强缓存 > 启发式缓存(未配置强缓存,本质上属于强缓存的一种特殊形态) > 协商缓存。

  也就是说启发式缓存的存在是一种兜底策略,是为了在服务器没有明确指定缓存策略时,仍然能够在一定程度上利用缓存提升性能。然而,由于启发式缓存是基于时间推断的,它可能会导致缓存资源过早失效或过晚更新,因此在实际应用中应谨慎使用。

欢迎大家关注我的个人博客:https://puppy.xin

相关推荐
数据掘金5 小时前
百度统计后台页面数据异常?从手动调用时机开始排查
前端
hunteritself5 小时前
10 层 4K 实时剪辑,国产工作站进入广电制作核心
大数据·前端·人工智能·深度学习·transformer
踩着两条虫5 小时前
我在浏览器里“盖”了一个村:Vue + Three.js 大屏开发踩坑记
前端·vue.js·three.js
mbshqqb5 小时前
TypeScript基础教程之同步生成器
前端·javascript·typescript
嘟嘟同学和妮妮同学5 小时前
【升级】一个中国历史可视化站:皇帝时间线梳理、古代思想流派、诗词鉴赏 (2)
前端·html
暗夜行者之光6 小时前
LangGraph + MCP 实战:构建"自然语言查数据"的 ChatBI Agent
前端·后端
一tiao咸鱼6 小时前
还在手动海投?我做了个 AI 求职助手,自动筛选 BOSS 职位再精准投递
前端·后端·面试
尤水就下6 小时前
🔥预热:在线文档的 block 架构是如何实现的(未完待续...)
前端·javascript·架构
全栈项目管理程序猿6 小时前
ArcGIS JS 基础教程(29):CSVLayer 表格点位图层
前端·javascript
骑着蜗牛撵大象3277 小时前
豆包 Seed 驱动的记账智能体:从拍票抽取到月报生成的全链路落地记录
java·前端·javascript·结构化输出·豆包seed·多模态识别·记账系统