保障缓存失效时用户体验的核心是“让用户无感”,通过stale-while-revalidate实现秒返旧内容+后台刷新,并配合分层响应、异步更新、降级兜底与缓存锁机制。

缓存失效期间保障用户体验流畅,关键不是避免失效,而是让失效“不被用户感知”——通过分层响应、异步更新和降级兜底,把“等新内容”变成“先看旧内容,后台悄悄换”。
用 stale-while-revalidate 实现“秒返旧内容 + 后台刷新”
这是最核心的体验保障机制。当缓存过期时,Nginx 不让用户等待后端响应,而是立即返回已过期但可用的内容,同时在后台发起一次异步请求去拉取新版本。
- 必须启用:
proxy_cache_use_stale updating;(允许返回正在更新中的过期缓存) - 配合开启后台更新:
proxy_cache_background_update on; - 响应头建议加上:
add_header Cache-Control "public, max-age=900, stale-while-revalidate=1800";,明确告诉浏览器也可复用过期资源并自行触发验证
为不同内容类型设置差异化的过期与降级策略
不是所有页面都适合返回旧内容,要按业务语义分级处理:
-
静态资源(JS/CSS/图片):设长 TTL +
immutable,基本不走失效逻辑;URL 版本化确保变更即新 key -
核心动态页(首页、商品列表):TTL 设为 15–30 分钟,同时启用
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;,后端挂了也敢返回旧版 -
强时效接口(订单状态、账户余额):默认不缓存;若需缓存,必须将用户标识(如
$cookie_user_id)纳入proxy_cache_key,并禁用stale类指令,避免错乱
防雪崩:用缓存锁 + 超时兜底控制并发回源
缓存集体失效时,大量请求穿透会瞬间压垮后端。Nginx 提供轻量级协调机制:
- 开启缓存锁:
proxy_cache_lock on;,同一 key 只放行首个请求回源 - 设置锁等待上限:
proxy_cache_lock_timeout 3s;,超时后直接返回当前缓存(含过期内容),不排队不阻塞 - 搭配
proxy_cache_use_stale updating;,确保锁释放前用户已有内容可看
兜底 HTML 页面:网络彻底断连时的最后一道防线
当后端完全不可达(DNS 失败、全链路超时),连“过期内容”都拿不到?那就返回一个本地维护页:
- 准备轻量
maintenance.html,不含外部资源引用,纯静态 HTML + 内联 CSS - 配置:
error_page 500 502 503 504 /maintenance.html; - 单独声明 location:
location = /maintenance.html { root /usr/share/nginx/html; },绕过 proxy_pass,完全脱离后端











