要让特定动态接口既不读缓存也不写缓存,必须协同配置 proxy_cache_bypass 和 proxy_no_cache,并用 map 拆解路径、响应头等为独立布尔变量,在 http 块统一定义,default 全设为 0,location 中成对启用二者,避免误伤静态资源与匿名流量,再通过响应头和日志验证生效。

要让特定动态接口既不读缓存、也不写缓存,关键不是只配 proxy_no_cache,而是让它和 proxy_cache_bypass 协同工作,并用状态码与路径共同决策——否则容易出现“绕过了读,却把敏感响应又存进去了”的问题。
用 map 提取路径与状态信号,生成统一布尔变量
直接在 proxy_no_cache 里写正则或嵌套判断难维护、易漏判。应把路径特征和响应状态拆解为独立、可验证的 0/1 变量,全部定义在 http 块中:
- 匹配敏感路径:
map $request_uri $no_cache_by_path { ~*^/api/v1/user/profile 1; ~*^/admin/logs 1; default 0; } - 拦截非 200 响应(如调试接口返回 401/500):
map $upstream_http_content_type $no_cache_by_status { ~*application/json 1; default 0; }(注意:Nginx 无法直接获取后端返回的状态码,但可通过$upstream_http_*获取响应头间接判断;若需精准按状态码控制,应在后端统一加标识头,如X-Cache-Control: no-store,再用map $upstream_http_x_cache_control $no_cache_by_header { "no-store" 1; default 0; }) - 避免误伤:所有
map的default必须设为0,确保未匹配请求默认走缓存流程
location 中必须成对启用 bypass 和 no_cache
这两个指令需传入完全相同的变量列表,Nginx 对它们的触发逻辑一致:任一变量值为 1,整条请求就全程脱离缓存链路:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
-
proxy_cache_bypass $no_cache_by_path $no_cache_by_header;→ 请求阶段跳过缓存查找,直连后端 -
proxy_no_cache $no_cache_by_path $no_cache_by_header;→ 响应阶段禁止写入缓存,防止错误状态或敏感内容被缓存 - 二者缺一不可:只开
bypass不开no_cache,后端返回的 500 或调试数据仍可能被缓存;只开no_cache不开bypass,请求仍会先查缓存(命中则直接返回旧数据)
排除静态资源与匿名流量,守住缓存友好底线
缓存策略的核心是“保稳求精”,不是全盘绕过:
- 不要在
http块全局写proxy_no_cache $cookie_sessionid—— 空 cookie 会被当作非空字符串,导致未登录用户也被绕过 - 对
/static/、/images/、.js、.css等路径单独配置location,跳过上述 map 判断,改用expires或proxy_cache_valid管理生命周期 - 若需灰度控制,可用自定义 header(如
X-Abtest-Flag),对应写map $http_x_abtest_flag $no_cache_by_abtest { "on" 1; default 0; }
验证是否真正生效:看响应头 + 日志联动
上线后务必检查实际行为,不能只看配置:
- 发起测试请求:
curl -H "X-Cache-Control: no-store" https://yoursite.com/api/v1/user/profile - 响应头中不应出现
X-Cache: HIT;理想是X-Cache: MISS或无此头 - 日志中
$upstream_cache_status应显示BYP(bypass)或MISS,而非HIT - 若仍命中缓存,先确认该请求是否真走了你写的 location 块(可在日志中打印调试变量,如
log_format debug '$remote_addr - $request_uri $no_cache_by_path $no_cache_by_header';)










