我有一个位置块设置来捕获所有文件请求并将它们发送到PHP-FPM
:
location / {
try_files $uri /routing.php?$args;
fastcgi_pass unix:/opt/local/var/run/php54/php-fpm-www.sock;
include /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}
这有效并且正确地将请求传递给PHP-FPM
所请求的确切现有 php 文件或routing.php
设置为要运行的脚本。
我尝试添加一个错误页面,这样如果路由文件被删除或者不可用,就会显示错误页面,而不是 Nginx 的默认错误页面:
location / {
try_files $uri /routing.php?$args /50x_static.html;
fastcgi_pass unix:/opt/local/var/run/php54/php-fpm-www.sock;
include /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}
这将停止routing.php
提供文件,并显示 50x_static.html 页面。对现有 PHP 文件的请求仍然有效,即转到 URL/dynamic.php
我意识到try_files
命令中的最后一个参数有点神奇:
如果找不到文件,则会调用内部重定向到最后一个参数。请注意,只有最后一个参数会导致内部重定向,前一个参数只会设置内部 URI 指针。最后一个参数是后备 URI,必须存在,否则将引发内部错误。
在调查 error_page 为何破坏配置时,我意识到对于有效的配置(没有静态错误页面),根据 Nginx 重写日志,Nginx 在尝试获取根 URL“/”时似乎匹配了两次请求:
"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(\w+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/proxy/(\d+)/(.+)\.(gif|png|jpg|jpeg|GIF|PNG|JPG|JPEG)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
"^/staticImage/(\w+)/(.+)\.([^\.]*)$" does not match "/routing.php", client: 127.0.0.1, server: basereality.com, request: "GET / HTTP/1.1", host: "basereality.test"
即,请求以 的形式传入/
,try_files
无法提供文件,因此将请求从 重写/
为/routing.php
,然后重新处理该请求。
为什么尝试文件routing.php
在第一次传递时不提供文件?该文件存在并且可以访问,否则第二次传递时就不会提供该文件。
编辑
删除了不相关的配置。
答案1
您引用的文档明确指出“调用了对最后一个参数的内部重定向”。内部重定向的处理方式与来自客户端的初始请求相同 - 这包括rewrite
在服务器级别处理语句,您可以在日志中看到这些语句。但是,如果除最后一个参数之外的任何其他参数与现有文件匹配,则将使用语句所在的配置try_files
来处理请求,并且不会有第二次匹配。location
try_files
至于您的规则,您是否尝试过$args
省略try_files
?
location / {
try_files $uri /routing.php /50x_static.html;
fastcgi_pass unix:/opt/local/var/run/php54/php-fpm-www.sock;
include /documents/projects/intahwebz/intahwebz/conf/fastcgi.conf;
}
请注意,$uri
不包含$args
太多;查询参数仍将通过参数传递给 FastCGI 后端QUERY_STRING
,该参数大概在您的中设置fastcgi.conf
:
fastcgi_param QUERY_STRING $query_string;
如果文件不$uri
存在/routing.php
,则请求将被重定向到配置中的部分/50x_static.html
并根据该location = /50x_static.html
部分进行处理(但仍将执行第二次重写尝试,因为重写规则放在服务器级别)。
您的配置中有一个非常可疑的细节,即无论文件扩展名是什么,您都通过 PHP 传递所有文件 - 这是非常不寻常的,并且可能会由于在非预期的文件中执行 PHP 代码而导致安全问题。
答案2
Sergey 的说法是正确的;$args
在 try_files 命令中添加内容会阻止文件匹配,因此会将 Nginx 送入另一个处理循环,这很奇怪,因为这就是 Nginx例如说要做。
如果你严格按照这个例子来做:
try_files $uri $uri/ /index.php?q=$uri&$args;
如果$uri
和$uri/
不存在,Nginx 将转到最后一个神奇参数。它甚至不会尝试匹配文件,而是重新处理请求,将新路径设置为 ,现在的/index.php
和设置为。$args
q=$uri&$args
另一方面,如果你在try_files
index.php 之后有另一个值,例如
try_files $uri $uri/ /index.php?q=$uri&$args /50x_static.html;
Nginx 查找一个名为的文件/index.php?q=$uri&$args
,但显然它不存在,因此它转到/50x_static.html
并重新处理该文件。
因为$uri
Nginx 重新处理请求时会重写,所以要避免这种情况需要进行一些细微的更改。如果您将配置设置为如下形式:
set $originalURI $uri;
try_files $uri $uri/ /index.php /50x_static.html;
fastcgi_param QUERY_STRING q=$originalURI&$query_string;
Nginx 查找的文件是/index.php
正确名称的文件,因此 nginx 将停止处理。我们必须在修改$uri
变量时复制它,因此如果我们在 try_files 之后使用它,try_files
那就公平了。/index.php