nginx 默认不缓存非幂等请求,但需显式配置拦截;应通过 map + proxy_cache_bypass 禁用 post/put/delete 缓存,对敏感路径禁用缓存,谨慎缓存幂等 post 并确保缓存键唯一,配合日志与响应头验证。

Nginx 默认只缓存 GET 和 HEAD 请求,对 POST、PUT、DELETE 等非幂等方法默认不缓存——但这不是“安全默认”,而是“不干预默认”。真正可靠的缓存策略必须显式定义,否则容易因上游响应头(如错误设置的 Cache-Control: public)或路径误匹配导致状态错乱。关键在于按请求方法精准分流,而非依赖隐含行为。
明确禁止非幂等方法进入缓存
非幂等请求一旦被缓存并复用,可能造成重复提交、数据覆盖或权限泄露。必须主动拦截:
- 用 map 将危险方法映射为非空值,再配合 proxy_cache_bypass 跳过缓存:
map $request_method $no_cache {
POST "1";
PUT "1";
DELETE "1";
default "";
}
location / {
proxy_cache_bypass $no_cache;
} - 对管理类、提交类路径,直接关闭缓存更稳妥:
location ~ ^/(api/v1/submit|admin|webhook) {
proxy_cache off;
} - 避免仅靠 if ($request_method != GET),Nginx 中 if 在 location 外使用有风险,且性能开销大。
谨慎启用幂等 POST 的缓存
某些 POST 实际是只读查询(如搜索、GraphQL 查询),可缓存,但需三重保障:
- 显式开启方法支持:
proxy_cache_methods GET HEAD POST;
注意:必须同时包含 GET 和 HEAD,Nginx 强制要求至少两个方法。 - 重写缓存键,确保不同请求体不混用:
proxy_cache_key "$scheme$host$request_uri$args$sha1($request_body)";
前提是 proxy_buffering on(默认开启),且 client_max_body_size 足够容纳典型请求体。 - 更推荐方案:让后端在响应头中返回签名(如 X-Req-Sign),Nginx 用 $http_x_req_sign 构建 key——避免直接读取 request_body 带来的不确定性。
按方法 + 路径 + 参数动态绕过
单一方法判断不够,需结合业务语义。例如:GET /order?user_id=123 是用户专属接口,不能缓存;而 GET /product?id=1001 是公共资源,可以缓存。
- 用 proxy_cache_bypass 组合多个变量,任一非空即跳过:
proxy_cache_bypass $arg_user_id $cookie_sessionid $http_authorization; - 对登录态敏感接口,可统一加判断:
location /user/ {
proxy_cache_bypass $cookie_sessionid $arg_token;
} - 避免将 $request_uri 直接用于 key,它不区分大小写且忽略参数顺序,易引发冲突;优先用 $request_uri$is_args$args 或结构化签名。
验证与兜底机制不可省略
配置写完不等于生效,必须可观测、可审计:
- 强制添加调试头:
add_header X-Cache-Status $upstream_cache_status;
确保所有 POST 请求响应头中该值为 BYPASS 或 MISS,绝不能出现 HIT。 - 在日志格式中加入缓存状态和方法:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$upstream_cache_status" $request_method'; - 对支付回调、审核通知等关键 Webhook 路径,建议彻底禁用缓存:
location = /callback/payment {
proxy_cache off;
proxy_pass http://backend;
}











