Nginx不主动标记过期响应,而是通过proxy_cache_valid设TTL、proxy_cache_use_stale updating启用stale状态、add_header X-Cache-Status显示STALE标识、proxy_cache_lock防击穿来实现过期内容的可控返回。

Nginx 本身不提供“主动标记过期响应”的独立机制,它通过缓存状态判断 + 响应头控制 + 配置策略协同来体现和管理“过期”这一概念。所谓“标记过期”,实际是指让 Nginx 在响应中明确传达:该内容已过期、正被使用但正在后台更新、或需重新验证。关键不在打标签,而在配置如何表达和处理这个状态。
以下是真正有效、生产可用的实现方式:
明确设置缓存有效期(基础前提)
没有 proxy_cache_valid 或 expires,Nginx 就无法识别“何时过期”。
必须为不同响应码设定合理 TTL:
proxy_cache_valid 200 301 302 5m; # 正常响应缓存 5 分钟 proxy_cache_valid 404 10s; # 404 缓存仅 10 秒,避免长期占位 proxy_cache_valid any 1m; # 其他状态统一缓存 1 分钟
⚠️ 若未配置,Nginx 默认不缓存(或仅按上游 Cache-Control/Expires 头决定),整个过期逻辑失效。
启用 stale 状态支持(让“过期”可被返回)
默认情况下,缓存一过期,Nginx 就阻塞等待回源——用户会感知延迟。要让它“返回旧内容并后台更新”,必须显式授权:
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
其中 updating 是核心:它允许 Nginx 在后台刷新缓存时,仍把已过期但尚未更新完成的内容返回给用户。
添加可观察的状态标识(用于验证和调试)
靠响应头直观确认当前响应是否来自过期缓存:
add_header X-Cache-Status $upstream_cache_status;
你会看到这些值:
-
HIT:缓存新鲜,直接返回 -
MISS:无缓存,回源生成并缓存 -
STALE:缓存已过期,但正在用旧内容 + 后台悄悄更新中 ✅ 这就是你想要的“被标记为过期但仍服务”的状态 -
REVALIDATED:收到If-Modified-Since或If-None-Match,后端返回304,缓存续期
防并发击穿(保障 stale 行为稳定)
高并发请求同一过期 key 时,若不加锁,可能触发大量重复回源。启用锁机制:
proxy_cache_lock on; proxy_cache_lock_timeout 5s; # 等待锁超时后,直接走 stale 路径
这样确保只有一个请求真正回源,其余都拿到 STALE 响应,既保护后端,又维持用户体验。
补充:静态资源建议用 URL 版本化替代“过期标记”
对 JS/CSS/图片等,更可靠的做法是让过期逻辑前置到路径层:/static/app.a1b2c3.js → 配置强缓存 expires 1y;
文件名变,URL 变,缓存自然失效。这种方式比依赖时间过期更精准、零误判,也无需标记 stale。
不复杂但容易忽略


















