stale-while-revalidate是一种HTTP缓存策略,允许浏览器在缓存过期后立即返回旧资源,同时后台异步发起验证请求;它确能“后台更新”,但依赖浏览器自动执行、需配合max-age和ETag/Last-Modified,且仅对GET生效。

stale-while-revalidate 是什么,它真能“后台更新”吗?
stale-while-revalidate 不是让浏览器主动在后台拉新资源,而是告诉浏览器:当缓存已过期(stale)时,**先立即返回旧资源**,同时在后台悄悄发起一个异步请求去更新缓存。用户感知不到延迟,但下次访问就能用上新内容。
关键点在于:这个机制完全由浏览器控制,无需 JS 参与,也不依赖 Service Worker;但它只对 GET 请求生效,且必须配合有效的 Cache-Control: max-age=... 使用,否则浏览器可能直接跳过 stale 阶段。
- 必须有明确的
max-age,比如Cache-Control: max-age=60, stale-while-revalidate=300 - 服务器需对条件请求(如带
If-None-Match或If-Modified-Since)返回304 Not Modified,才能真正复用旧缓存并完成“后台更新” - 如果服务器忽略验证头、直接返回
200带完整响应体,浏览器会替换缓存,但浪费带宽
HTTP 响应头怎么写才生效?
后端设置响应头时,stale-while-revalidate 必须和 max-age 同时出现,且值为秒数(整数),不能带单位或小数:
Cache-Control: max-age=120, stale-while-revalidate=600
这表示:资源 2 分钟内直接用缓存;过期后 10 分钟内仍可立即返回旧内容,并后台刷新。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 不要写成
stale-while-revalidate="600"(引号非法) - 不要漏掉
max-age—— 没它,浏览器认为资源不可缓存,stale-while-revalidate被忽略 - CDN(如 Cloudflare、Fastly)通常支持该指令,但 Nginx 默认不解析它,需确认版本 ≥ 1.19.1 且启用
proxy_cache_use_stale updating
为什么改了资源,用户还是看到旧内容?
常见原因是服务器没正确处理协商缓存:浏览器在后台发的请求带了 If-None-Match,但后端直接返回 200 + 新内容,而不是 304。结果是——缓存确实更新了,但用户这次看到的仍是旧版本(因为“先返回旧资源”逻辑已执行完毕),而下次才会用新版本。
- 检查日志:确认后台请求是否收到
If-None-Match头,并对应返回304 - 静态资源(如 JS/CSS)建议加哈希文件名,避免依赖协商缓存;
stale-while-revalidate更适合动态 HTML 或 API 响应这类无法重命名的内容 - Chrome DevTools 的 Network 标签页里,后台更新请求会显示 (disk cache) 或 (stale), 但不会标“revalidation”——得看请求头和状态码判断
Node.js/Express 中如何安全设置?
用 res.set() 直接写头最稳妥,注意别被中间件覆盖:
res.set({
'Cache-Control': 'max-age=300, stale-while-revalidate=600',
'ETag': '"abc123"' // 或用 etag:true 自动计算
});
如果你用 express.static(),默认不设 stale-while-revalidate,需自行包装或改用 serve-static 并传入 setHeaders:
app.use(express.static('public', {
setHeaders: (res, path) => {
res.set('Cache-Control', 'max-age=300, stale-while-revalidate=600');
}
}));
- 不要在
res.header()后再调res.send()时又设一遍 Cache-Control —— 会覆盖 - 动态内容慎用大
stale-while-revalidate值,比如新闻首页设 1 小时,用户可能长时间看不到突发更新
stale-while-revalidate 的后台请求就变不成 304,而是白跑一趟 200。


















