Nginx 中 rewrite 先于 try_files 执行,需用 break 确保重写后继续执行 try_files;last 则重启匹配,适合分离静态与动态逻辑;务必显式加标志、锚定正则、拼接 query_string 并慎用 root/alias。

Nginx 中 try_files 和 rewrite 可以配合使用,但必须注意执行顺序和作用域——它们不是随意叠加的工具,而是有明确优先级和适用场景的指令。核心原则是:try_files 本身不触发重写,它只做文件/路径存在性检查与内部跳转;而 rewrite 在 location 块中默认是“重写后重新匹配”,可能引发循环或覆盖 try_files 的意图。 要实现可靠、可维护的复杂伪静态,关键在于合理划分阶段、控制重写时机,并避免隐式循环。
理解执行顺序:rewrite 先于 try_files(在同个 location 内)
在同一个 location 块中,Nginx 按配置顺序处理指令:rewrite 语句先执行(若匹配成功且未加 last/break 标志),之后才轮到 try_files。但更关键的是 rewrite 的标志决定后续行为:
-
rewrite ... last;→ 终止当前 location 匹配,**重新发起请求匹配流程**(即再次走 server → location 匹配),此时原try_files不再生效 -
rewrite ... break;→ 终止 rewrite 链,**不重新匹配 location**,继续执行该 location 内后续指令(如try_files) -
rewrite ... redirect;或permanent;→ 发送 HTTP 重定向,不执行后续指令
用 break + try_files 实现“重写后尝试静态资源”
这是最常用也最安全的组合:先用 rewrite 规范 URL 结构(比如把 /post/123 改成 /index.php?post_id=123),再用 try_files 判断真实文件是否存在,不存在才交由后端处理。适用于 WordPress、Typecho 等 PHP 应用的伪静态需求:
location / {
# 把 /post/123 → /index.php?post_id=123(内部重写,不跳转)
rewrite ^/post/(\d+)$ /index.php?post_id=$1 break;
<pre class="brush:php;toolbar:false;"># 尝试命中真实文件、目录,否则交给 index.php
try_files $uri $uri/ /index.php?$query_string;}
注意:break 是关键,它确保 rewrite 后继续执行 try_files,而不是重启匹配导致无限循环或误入其他 location。
用 last + 精确 location 分离静态与动态逻辑
当伪静态规则较多、需区分静态资源(js/css/img)和动态路由时,推荐将 rewrite 放在通用 location,用 last 跳转到专用 location,在那里用 try_files 处理最终路径:
# 主入口:统一 rewrite 所有伪静态路径
location / {
rewrite ^/article/(\d+)$ /a/$1.html last;
rewrite ^/user/([^/]+)$ /u/$1.html last;
rewrite ^/(.*)$ /index.php?path=$1 last;
}
<h1>专门处理 .html 后缀的静态化页面(实际是 PHP 渲染)</h1><p>location ^~ /a/ {
try_files $uri /index.php?article_id=$uri;
}</p><p>location ^~ /u/ {
try_files $uri /index.php?username=$uri;
}</p><h1>真实静态资源直接返回,不进 PHP</h1><p>location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}</p>
这种结构清晰分离了“URL 映射”和“资源交付”,便于调试和扩展,也避免了在主 location 中堆砌大量 try_files 分支。
规避常见陷阱:循环、404 和 query_string 丢失
以下问题高频出现,需主动预防:
-
rewrite 循环:没加
last或break,又没设置匹配边界(如用^/post/而非/post/),导致反复重写。建议所有 rewrite 都显式加标志,并用^和$锚定 -
try_files 忽略 query_string:
$uri不含参数,$query_string需手动拼接。转发给 PHP 时务必带上,例如/index.php?$query_string或/index.php?path=$1&other=1 -
root 与 alias 混用导致 404:在带 rewrite 的 location 中,优先用
alias(尤其匹配路径含前缀时),避免root多拼一级目录。例如location /static/ { alias /data/assets/; }











