启用 fastcgi_cache_revalidate 可显著降低 nginx 与 php-fpm 的无效交互:缓存过期时,nginx 携带 if-none-match 向后端发起条件请求,php 返回 304 即可延长缓存,避免重复执行脚本、查库和渲染;前提为 php 正确生成反映内容变更的 etag,并配套配置 fastcgi_cache_valid、fastcgi_cache_revalidate、fastcgi_cache_use_stale 和规范的 fastcgi_cache_key,同时清除干扰响应头、禁用动态 cache_key 变量,并添加 x-cache 调试头。

直接用 fastcgi_cache_revalidate 配合 ETag,能显著降低 Nginx 和 PHP-FPM 之间的无效交互——它让 Nginx 在缓存即将过期时,不直接丢弃旧内容,而是带着 If-None-Match 头向后端发起条件请求,由 PHP 返回 304(Not Modified)来延续缓存有效期,避免重复执行 PHP 脚本、查库、渲染等整套流程。
启用 revalidate 的前提:后端必须输出合法 ETag
PHP 脚本需在响应头中明确设置 ETag,且值要反映内容真实变化。例如:
- 商品页可基于商品 ID + 最后更新时间生成:
header('ETag: "prod-123-' . $updated_at . '"'); - 避免使用随机值或固定字符串,否则无法触发 304,revalidate 就失效
- 确保不同时段的相同内容返回相同 ETag,不同内容返回不同 ETag
关键配置项必须协同生效
仅开启 fastcgi_cache_revalidate 不够,还需配套设置:
-
fastcgi_cache_valid 200 301 302 10m;—— 先给缓存设一个基础有效期(比如 10 分钟) -
fastcgi_cache_revalidate on;—— 启用“缓存再验证”机制 -
fastcgi_cache_use_stale updating error timeout http_500;—— 允许在 revalidate 过程中继续返回旧缓存(避免卡顿) -
fastcgi_cache_key "$scheme$request_method$host$request_uri";—— key 中不含时间戳或动态参数,保证同一 URL 复用缓存
实际交互流程:从“全量重刷”变成“轻量确认”
假设缓存原始有效期为 10 分钟,第 9 分 50 秒收到新请求:
- 旧缓存未过期 → 直接返回,不发请求到 FPM
- 旧缓存已过期(如第 10 分 05 秒)→ Nginx 携带
If-None-Match: "prod-123-202605281015"向 PHP-FPM 发起 HEAD 或 GET 请求 - PHP 检查当前内容 ETag 匹配 → 返回
304 Not Modified→ Nginx 延长该缓存有效期(默认延长原时长的一半,即再+5 分钟) - PHP 内容已变 → 返回
200+ 新内容 + 新 ETag → Nginx 更新缓存并返回
注意几个易错点
这些细节不到位,revalidate 很容易“形同虚设”:
- PHP 输出了
Cache-Control: no-cache或Pragma: no-cache,会覆盖 Nginx 缓存逻辑,必须清理或重写 - 未开启
fastcgi_ignore_headers Cache-Control Expires Set-Cookie,Nginx 可能因后端头拒绝缓存 - 使用了
$request_time或时间类变量参与fastcgi_cache_key,导致每次 key 都不同,缓存无法复用 - 未配置
add_header X-Cache "$upstream_cache_status";,调试时无法区分 HIT / REVALIDATE / MISS










