Nginx 中 proxy_cache_use_stale 可与 map 模块协同实现精细化降级:通过 map 动态控制 stale 开关、多级回源兜底及敏感请求过滤,但前提是缓存已存在且 key 稳定、5xx 响应被 cache_valid 明确缓存。

你提到的 proxy_cache_stale 实际上是笔误,Nginx 官方配置项为 proxy_cache_use_stale。它本身不直接“结合 map”,但 map 模块可与 proxy_cache_use_stale 协同构建分层、可控的降级路径:用 map 动态控制是否启用 stale、是否跳过缓存、是否走备用上游,从而实现按接口类型、错误码、请求特征差异化降级。
用 map 控制 stale 是否生效(精细化开关)
不是所有接口都适合返回陈旧数据。比如用户余额页必须强一致,而商品详情页可接受几分钟延迟。这时可用 map 根据 URI 或状态码动态决定是否允许 stale:
- 定义一个变量,标识当前请求是否允许 stale 降级:
map $request_uri $allow_stale {
default "0";
~^/api/product/.* "1";
~^/static/.* "1";
} - 在 location 中引用该变量,只对白名单路径启用 stale:
proxy_cache_use_stale http_502 http_503 http_504;
proxy_cache_use_stale error if=$allow_stale;(注意:Nginx 1.19+ 支持if=语法;旧版本需用if块包裹proxy_cache_use_stale)
用 map 实现多级回源 + stale 兜底(故障转移链)
当主 upstream 不可用时,先切到备用集群;若备用也失败,再 fallback 到 stale 缓存。map 可帮你把“上游健康状态”映射为不同行为:
- 定义 upstream 健康状态映射:
map $upstream_http_x_backend_status $fallback_level {
"primary_ok" "0";
"backup_ok" "1";
"all_down" "2";
} - 配合 if 或 rewrite 控制流程:
当$fallback_level = "2"时,跳过proxy_pass,直接启用 stale 并返回缓存内容(需提前确保该请求已缓存过);或触发自定义错误页:
if ($fallback_level = "2") {
add_header X-Fallback "stale-cache";
proxy_cache_use_stale error http_502 http_503 http_504;
break;
}
用 map 过滤敏感请求,避免 stale 误伤
某些带用户态参数(如 ?uid=123、&token=xxx)或埋点路径(如 /log/track?id=xxx)绝不能走 stale,否则会返回他人数据或污染日志。map 可提前识别并关闭缓存:
- 标记高危请求:
map $args $skip_cache {
~uid=|token=|log/track "1";
default "0";
} - 在 location 中联动:
proxy_cache_bypass $skip_cache;
proxy_cache_use_stale error http_502 http_503 http_504 if=$skip_cache;(即:若本该跳过缓存,则也不允许 stale;真正需要 stale 的,仅限已缓存且非敏感路径)
关键前提:stale 能生效,永远依赖缓存本身存在
map 再灵活,也无法凭空造出缓存。要让上述降级路径真正可用,必须同步保障:
- proxy_cache_path 已定义 keys_zone,且 location 中正确引用
-
proxy_cache_key 稳定(推荐
"$scheme$host$request_uri"),不含随机 traceid、时间戳、用户 cookie -
proxy_cache_valid 明确覆盖 5xx 响应(如
proxy_cache_valid 502 503 504 1m;),否则错误响应根本不会进缓存,stale 就无旧内容可返 - add_header X-Cache $upstream_cache_status; 必须开启,才能从客户端验证是否真实命中 STALE











