try_files 指令按序检查文件或目录存在性,依赖 root(或 alias)定义的根路径;非末尾参数拼接 root 后检查文件/目录,末尾参数触发内部重定向;$uri 不自动去斜杠,拼接需防重复“/”;调试用 $request_filename 和 $document_root 日志验证路径。

在 Nginx 中,root 指令本身不决定请求匹配逻辑,真正控制“先查什么、再试什么”的是 try_files。它的行为高度依赖于 root(或 alias)定义的文件系统路径基址,且每个参数都按顺序严格求值——只要某一项存在(文件或目录),就立即返回对应资源,后续项不再检查。
try_files 参数逐项求值,不跳过、不回溯
try_files 后面列出的所有路径(除最后一个外)都会被拼接到 root(或 alias)路径下,作为真实文件系统路径进行存在性检查。Nginx 从左到右依次判断:
- 对每个非末尾参数,先检查是否为 存在的普通文件;如果是,直接返回该文件(状态码 200)
- 若不是文件,则检查是否为 存在的目录;如果是,且该目录下有 index 文件(如 index.html),则内部重定向到该目录的 index 资源
- 若当前项既不是文件也不是目录,继续检查下一个参数
- 直到遇到最后一个参数:它被当作 内部重定向 URI(不是文件路径),无论是否存在,都会触发一次新的 location 匹配流程
root 和 try_files 的路径拼接规则必须明确
root 定义的是“静态资源根目录”,try_files 中各参数是相对于该根目录的相对路径。注意:
-
root /var/www;+try_files $uri /index.html;→ 实际检查/var/www/$uri和/var/www/index.html -
$uri是原始请求 URI(如/app/js/main.js),不会自动去除开头的/,所以拼接后是/var/www/app/js/main.js - 不要写成
try_files $uri /$uri /index.html;—— 第二个/$uri会多拼一个/,变成/var/www//app/js/main.js,通常不存在 - 如果用
alias替代root,拼接逻辑不同:alias会**替换** location 前缀,需格外小心路径对齐
常见陷阱:末尾斜杠、目录访问与内部重定向
当请求以 / 结尾(如 GET /admin/),$uri 就是 /admin/。此时:
-
try_files $uri $uri/index.html =404;→ 先查/var/www/admin/是否为目录,是则尝试加载/var/www/admin/index.html -
try_files $uri /index.html;→ 若/var/www/admin/是目录,直接成功返回(Nginx 自动找 index);但若只是想 fallback 到根 index,这个写法没问题 -
try_files $uri @fallback;→ 最后一项@fallback是命名 location,触发内部重定向,不走文件系统检查,适合代理或重写场景 - 误写
try_files $uri /$uri/ /index.html;可能导致双重斜杠或无限循环(如请求/a时去查/a/,而/a/又匹配同一条规则)
调试技巧:用 error_log 和 log_format 观察实际路径
在 server 或 location 块中加入:
log_format debug '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$request_filename" "$document_root"';access_log /var/log/nginx/debug.log debug;error_log /var/log/nginx/error.log notice;
其中 $request_filename 显示 Nginx 实际要打开的文件路径,$document_root 显示当前生效的 root 路径,可精准验证拼接结果。配合 curl -I http://localhost/xxx 查看响应头和日志,快速定位 404 是因路径错、权限问题,还是根本没走到预期 location。

















