理解 Nginx 的 try_files
Nginx 的 try_files
指令实在有趣!它比乍看上去更有深度。
首先,Nginx 几乎可以不需要 try_files
。没有它,Nginx 为静态文件提供服务也没问题:
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.html index.html;
}
如果要支持 PHP,可以这样:
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.html index.html;
location ~ \.php$ {
# pass off to PHP-FPM via fastcgi
}
}
这实际上适用于静态文件和PHP应用的主页。一旦我们将路径引入到 URI(比如 example.com/foo/bar
),它会崩溃。这便是使用 try_files
的时候。
添加 try_files
try_files
指令将会贯穿每个给定的选项,以尝试使用指令查找一个文件是否存在于服务器中。
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.html index.html index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
}
对于给定的 URI,这段代码:
$uri
选项让 try_files
将该 URI 作为相对于根目录 root
的磁盘文件查找,本例为 /var/www/html/public
。
1️⃣ /css/app.css
URI 将会搜索 /var/www/html/public/css/app.css
。
2️⃣ URI /foo/bar
将有 2 种行为 - 一个用于目录存在,一个用作不存在
首先,$uri/
选项让 try_files
将该 URI 当作目录并确认目录是否存在。如果 URI 关联到一个现有目录, Nginx 需要计算为该目录的哪个文件提供服务。
这便是 index
指令起作用的地方。由于 Nginx 只知道目录存在,我们需要通过 index
告诉 Nginx 哪些文件提供服务(如果文件存在)。你可以使用任何文件。第一个匹配的文件“胜出”。
3️⃣ 如果给定的 URI 匹配既不存在文件也不存在目录,那么 try_files
转到回退 URI - /index.php?$query_string;
。
其他 location 区块呢?
这个 location /
区块,以及其中的 try_files
指令,事实上与其他的 location
块一起生效!以下是稍微更完整的配置文件:
server {
listen 80;
server_name _;
root /var/www/html/foobar.com;
index index.html index.htm index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
# pass off to PHP-FPM via fastcgi
}
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico)$ {
expires 7d;
access_log off;
log_not_found off;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
如果该 try_files
指令解析/找到静态资源(css, js, 图片) 文件,那么第三个 locaction 块将实际处理该请求。这意味着 location / {}
和 location ~* \.(<stuff>)$ {}
块都与这一请求相关!
当使用 PHP 文件时,情况相同 - 使用 location ~ \.php$ {}
块:
- 当
index
解析到目录的index.php
- 当使用回退
/index.php?$requests_uri
- 当 URI 给定的 PHP 文件存在时
在这些情况下,try_files
找到由 location ~ \.php$ {}
块“匹配的” PHP 文件,这将请求传递给 PHP-FPM。这是为什么 404 错误(无论是静态文件还是应用路由不存在)通常从 PHP 应用种返回。所有“不能在磁盘种找到文件”的真实用例传递给 /index.php
并因此经由该配置的 FastCGI 代理将请求发送给 PHP 应用。