前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库HTTP 启发式缓存 heuristic freshness Last-Modified
HTHTTP缓存与代理

服务器没有返回 Expires 和 max-age 时,HTTP 缓存能否根据 Last-Modified 推断新鲜期,风险是什么?

能,但仅当状态码可启发式缓存且无显式新鲜度信息时,缓存按 Last-Modified 与 Date 差值的百分比估算新鲜期,存在资源已变化却仍被当新鲜的过期风险。

前端进阶之旅 · 一题精讲更新于 2026.09.05
HTTP#缓存与代理#缓存
先看核心答案
理解线索

启发式新鲜度推导

  1. 缺失显式指令无 Expires 或无 max-age 时触发
  2. 基准差用 Date 减 Last-Modified 得出
  3. 比例系数常见实现取差值的 10% 左右

该系数可配置,规范不强制精确值,缓存实现可调整。

核心回答

先记住这个答案

可以。当响应未携带 Expires 或 Cache-Control: max-age 时,若状态码允许启发式缓存,HTTP 缓存会用 Last-Modified 与 Date 的差值乘以约 10% 作为新鲜期。例如 Last-Modified 距今十天,则新鲜期约为一天。此估算依赖修改时间与内容变更强相关,风险是低频更新或动态内容会在估算期内被误当作新鲜,需靠条件请求或主动配置显式新鲜度来规避。

  • 启发式缓存是最后兜底,应避免依赖
  • 新鲜期约为 Last-Modified 到 Date 的 10%
  • 警惕启发式缓存导致过期内容继续服务

启发式新鲜期的计算与判定条件

当响应没有 Expires 也没有 Cache-Control 的 max-age 指令时,缓存仍可能存储并复用响应,前提是状态码被定义为可启发式缓存,例如 200、301、410 等。RFC 9111 第 4.2.2 节指出,若响应带有 Last-Modified,缓存可据此估算新鲜度:通常取 Date 与 Last-Modified 差值的一定比例,常见实现是 10%。这个比例并未硬编码为标准值,只要求是合理上限。

具体算法为:freshness_lifetime = (Date - Last-Modified) × 0.1。若响应没有 Last-Modified,则没有可用于启发式计算的基准时间,缓存通常会认为响应已过期并在下次请求时向源站重新验证。

APT 软件源频繁发布更新的失败场景

一个企业内网镜像服务器未配置 Cache-Control,偶尔通过 Last-Modified 透露软件包的修改时间。某软件包在一个月前被构建,Date 与 Last-Modified 相差约 30 天,于是缓存按 10% 估算出 3 天新鲜期。上午 10 点源站发布了安全补丁,但该包在缓存中仍被视为新鲜,最长 3 天内不会回源验证,客户端持续得到含有漏洞的旧包。

修复方式是停止依赖启发式缓存:源站为这类动态资源显式设置 Cache-Control: no-cache 或 max-age=0,并配合 ETag 做条件请求。若仍需短缓存,可设 max-age=60 并永远使用 Last-Modified 或 ETag 验证,使每次回源都能 304 且网络开销可控。这一改动避免发布后被动等待 TTL 自然过期。

启发式缓存的失效边界与运维代价

启发式缓存只在完全没有显式新鲜度信息时才起作用,一旦存在 Expires 或 Cache-Control,就会优先采用显式值。所以风险集中于配置缺失的旧服务器或第三方接口。另一个前提是状态码默认允许,如 404 响应也可被启发式缓存,但若 404 后来变为 200,在新鲜期内用户仍会看到页面丢失。

处理方法是审计没有缓存头的响应,为其补上合适的 Cache-Control。若无法改动源站,可在代理层规范化:添加 Cache-Control: no-cache 或统一 max-age 策略。代价是需要持续监控响应头变化,避免新路径再次漏配。开发者应把 Last-Modified 仅用作验证器而非新鲜度依据,真正可靠的是配套 ETag 或显式时间。

回答前,多想一步

容易答错的地方

Last-Modified 可精确反映内容变化
Last-Modified 精度只有秒级,同一秒内多次修改可能漏判;且服务器可自由设置该值,不保证与内容一致。它只适合弱验证,不能作为内容版本号。正确做法是优先使用 ETag 或显式新鲜度控制,Last-Modified 仅作回退。
没有缓存头就一定不会缓存
很多响应没有 Cache-Control 和 Expires,但浏览器仍会按启发式规则缓存,如那些 200 响应。若不想让浏览器缓存,应当显式发送 Cache-Control: no-cache 或 no-store,不能指望缺少响应头来防止存储。
试着用自己的话回答

面试官还会怎么问?

启发式缓存中 10% 比例是标准规定吗?

不是。RFC 9111 只要求启发式新鲜度应选用不会显著增加误用的比例,并没有给出具体的 10% 示例;10% 是 Chrome 等常见实现的选择,其他浏览器或中间缓存可能调整。

响应带有 Vary 头且未命中时,启发式新鲜度如何计算?

Vary 只影响缓存键,不影响新鲜度。未命中表示没有存储的表示,需向源站发完整请求;新响应若无显式新鲜度指令,仍可走启发式流程,其 Last-Modified 照常参与计算。

如果 Last-Modified 晚于 Date(时钟不一致)会怎样?

差值将变为负数,实现会将其视为零新鲜期,即缓存立即过期,每次请求都会回源验证。实际收益低,但不会错误延长缓存,可促使开发者修复时间偏差。

从一道题,走向一组知识

把知识连起来

缓存与代理

HTTP 缓存中「新鲜度」和「验证」分别解决什么问题,命中缓存的完整判定流程是怎样的?

启发式缓存决定新鲜期后再谈验证策略,两者共同构成完整命中判定。

缓存与代理

HTTP 条件请求中 Last-Modified 和 ETag 同时存在时客户端该用哪个,秒级精度会带来什么问题?

Last-Modified 在启发式中作时间基准,与 ETag 相比验证能力更弱。

参考资料

  • RFC 9111 - HTTP Caching

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 启发式新鲜期的计算与判定条件
  3. APT 软件源频繁发布更新的失败场景
  4. 启发式缓存的失效边界与运维代价
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑