前端进阶之旅前端进阶之旅
  • 基础篇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 Age 头计算 多级代理 Date RFC9111
HTHTTP缓存与代理

HTTP 缓存如何计算响应的当前 Age,经过多级代理时 Age 头与 Date 头怎样参与计算?

Age 头表示响应自源站生成后经过的秒数,多级缓存中需用响应时刻与 Date 差的 apparent age 与经 response_delay 校正的 corrected age 共同推算,而非直接沿用上游 Age。

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

Age 推导的输入与输出

  1. apparent_age当前响应时间减去本响应的 Date,下限为0
  2. response_delay收到请求到收到响应的时间差,补偿上游延迟
  3. resident_time本缓存从存入到取用之间的等待时长

corrected_initial_age 取 apparent_age 与 age_value+response_delay 中的较大者,不能只用前者。

核心回答

先记住这个答案

计算当前 Age 时,先得到 apparent_age = max(0, response_time - date_value),再以 corrected_age_value = Age 头值 + response_delay 做校正,取二者较大值作为初始年龄,加上本缓存驻留时间即得当前 Age。多级代理中 Date 保持不变,每跳都按这段逻辑重新计算 Age 并透传,从而补偿传输延迟和本地停留。

  • apparent_age 是响应时间与 Date 的差
  • 每级代理都要加 response_delay 校正
  • Age 在多级缓存中逐跳累加且 Date 不改

RFC 9111 中 age_value 的两步校正机制

缓存收到响应时先记录 request_time 与 response_time。第一步算 apparent_age,它是响应时刻减 Date 的值;由于 Date 表示源站生成时刻,这个差说明了响应已经存在多久。若当前节点时钟比源站慢,差的负会被钳为 0,所以用 max(0, ...) 规避时钟差异造成负年龄。

第二步看 Age 头携带的年龄以及本段传输耗时。corrected_age_value = Age 头数值 + (response_time - request_time),这是假设上游 Age 是相对真实时间估算出的,再补齐本段中间的转发延迟和排队。最终 corrected_initial_age = max(apparent_age, corrected_age_value);此后只要缓存未取出使用,年龄随当前时间继续增加。

两端子级联传输的具体计算

设源站 Date 为 12:00:00,第一级代理 C1 的 request_time=12:00:05、response_time=12:00:10。C1 的 apparent_age=10 秒,Age 头为空,response_delay=5 秒,故 corrected_age_value=5,取大者初始年龄=10,且 C1 在 12:00:10 存储后到 12:00:15 被下一级请求,resident_time=5,因此转发时 Age 头应写 15。

客户端后接的 C2 在 12:00:15 发出请求,收到响应时是 12:00:18,Date 仍是 12:00:00。C2 先取 Age 头 15,计算 response_delay=3,corrected_age_value=18;而 apparent_age=18,max(18,18) 得初始年龄 18,不久后给浏览器用时 Age 为 18。路径上总延迟 8 秒被两跳的本地驻留和传输正确反映,而不是只依赖源站 Date。

时钟偏移和传输欠载下的失效边界

若中间某级机器时钟明显快于源站,apparent_age 会被放大,可能超过真实年龄,而 max() 无法排除偏快程度,导致 Age 高估;若时钟慢,则 apparent_age 被钳为 0,可能低估 Age。corrected_age_value 依赖上游 Age 头,但当 apparent_age 更大时仍会被采用,因此最终 Age 可能失真,需依赖 NTP 同步减小误差。若上游 Age 头被清空,则失去该参考依据。

另一个边界是重验证场景。当缓存持有陈旧响应发起验证并收到 304 时,Date 仍是源站原始时间,而 response_time 是新时间,apparent_age 会包含缓存驻留时长,但 response_delay 仅反映本段验证请求的延迟,因此 corrected_age_value 可能低于真实年龄。RFC 9111 的 4.3.4 节规定了验证后的处理,并非简单将 Age 重置为 0,需依据响应头更新存储,避免陈旧 Age 误叠加。

回答前,多想一步

容易答错的地方

只把 Date 与当前时间差当 Age
即使 Date 是源站生成时间,直接从 Date 推导出的 apparent_age 忽略了代理间的转发耗时。若不加上 response_delay 并参考上游 Age,多级链路会低估实际年龄,导致本已过期的响应被当作新鲜发送。正确做法是取 apparent_age 和 age_value+response_delay 中较大者。
每级缓存的 Date 都重写为本地时间
Date 头在转发时必须保留源站原始值,只能通过 Age 头表示增量。若改动 Date,各入口计算 apparent_age 会直接错乱,之前的 Age 也失去基准。每级只应修改 Age,除特定兼容处理外不得改写 Date。
试着用自己的话回答

面试官还会怎么问?

如果中间某级缓存与源站时钟差异超过十秒,Age 还可靠吗?

reliability 依赖上游 Age 和 response_delay 的补偿。时钟差异过大时 apparent_age 失真,但 corrected_age_value 不受影响,仍可作为备选。只有同时缺少 Age 头且 response_delay 很小才会可能明显误判;生产上建议各层保持 NTP 同步并显式携带 Age。

Age 超过响应新鲜度后,缓存是否一定回源?

不一定。Age 只表示响应存在时间,新鲜度判断还需看本地请求的 max-age 等指令;若允许 stale-while-revalidate 或 max-stale,缓存仍可先用旧响应并后台验证。Age 越大越可能触发回源,但并非唯一判据。

Age 头由源站生成后在多个代理中透传,接收方需要重新累加吗?

每个缓存或代理在转发前都必须按自身记录位置重新计算 Age,而不能简单透传。即便上游 Age 正确,本段驻留时间也必须靠 response_time 回推补入,否则最终消费者看到的 age 过小。

从一道题,走向一组知识

把知识连起来

缓存与代理

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

同属「缓存与代理」专题,接着看 HTTP 启发式缓存 heuristic freshness Last-Modified 在具体场景中的处理方式。

缓存与代理

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

同属「缓存与代理」专题,接着看 HTTP 缓存 fresh stale 验证 流程 在具体场景中的处理方式。

参考资料

  • RFC 9111 - HTTP Caching

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

本题目录
  1. 先记住这个答案
  2. RFC 9111 中 age_value 的两步校正机制
  3. 两端子级联传输的具体计算
  4. 时钟偏移和传输欠载下的失效边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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