expires 指令与 try_files 指令无直接优先级冲突,因作用阶段不同:try_files 先决定响应体来源(内容分发),expires 后添加缓存响应头;仅当响应由当前 location 直接生成时,expires 才生效。

Nginx 中 expires 指令和 try_files 指令本身不直接竞争优先级,因为它们作用阶段不同:前者控制响应头(缓存策略),后者决定请求如何匹配文件或内部重定向。但二者在实际配置中常共存,容易让人误以为存在“谁生效”的冲突。关键在于理解 Nginx 的处理流程——try_files 先执行(内容分发决策),expires 后生效(响应头注入),且仅对最终返回的响应起作用。
try_files 决定“返回什么”,是缓存逻辑的前提
try_files 在 location 块中运行,按顺序检查文件或 URI 是否存在,并终止于第一个匹配项。它不生成响应头,只决定响应体来源(静态文件、内部重定向、或 fallback)。只有当最终响应由当前 location 产生(比如命中本地文件)时,该 location 中的 expires 才会应用。
- 若
try_files $uri @backend命中$uri(如/logo.png存在),则进入该 location 的后续处理,expires生效 - 若未命中,跳转到
@backend(如 proxy_pass),此时原 location 的expires不再适用,需在@backend对应的 location 或 upstream 响应中控制缓存头 - 注意:
try_files触发的内部重定向(如try_files $uri /index.html)仍留在同一 location,因此后续的expires依然有效
expires 只修饰“本 location 实际发出的响应”
expires 是一个响应头指令,它不会改变请求流向,只在响应即将发出前添加 Expires 和 Cache-Control。它的作用对象必须是当前 location 直接提供的响应:
- 对
proxy_pass、fastcgi_pass等代理响应,expires默认不生效(除非开启expires -1强制清除,或使用add_header覆盖) - 对静态文件服务(
root/alias),只要 location 匹配且try_files最终落在此处,expires就会写入响应头 - 常见误区:在 proxy location 里写
expires 1h,但后端已返回Cache-Control: no-cache,此时 Nginx 默认不会覆盖——需显式用proxy_ignore_headers Cache-Control Expires;+expires才能强制生效
典型配置中的协同与陷阱
单页应用(SPA)常用如下结构:
location / {
try_files $uri $uri/ /index.html;
expires 1h;
}
这里逻辑清晰:$uri 存在(如 JS/CSS)→ 返回文件并带 1h 缓存头;不存在 → 回退到 /index.html(仍在此 location)→ 返回 HTML 并同样带 1h 缓存头。但问题在于 HTML 通常不该长期缓存。正确做法是拆分 location:
- 为静态资源(
/.+\.(js|css|png|jpg))单独 location,配expires 1y - 为根路径或 HTML 路径设另一 location,配
expires 0或add_header Cache-Control "no-cache" - 确保
try_files的 fallback(如/index.html)落在缓存策略合理的 location 中
调试建议:看实际响应头,而非配置顺序
判断缓存是否生效,最可靠方式是用 curl -I 查看真实响应头:
- 如果看到
Cache-Control: max-age=3600,说明expires已触发 - 如果看到
Cache-Control: no-store或为空,检查是否被 upstream 响应头覆盖,或try_files实际跳转到了无expires的 location - Nginx 日志中启用
$sent_http_cache_control变量,可记录每条响应实际发出的缓存头










