nginx try_files处理两次,如果错误后备设置失败

我有一个位置块设置来捕获所有文件请求,并将它们发送到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命令中的最后一个参数有点神奇:

在没有find文件的情况下,调用到最后一个参数的内部redirect。 请注意,只有最后一个参数会导致内部redirect,前者只是设置内部URI指针。 最后一个参数是回退URI并且必须存在,否则会引发内部错误。

在调查为什么error_page破坏了configuration的时候,我意识到对于工作的configuration(没有静态错误页面),当试图获取根URL“/”时,根据Nginx重写日志,Nginx确实似乎匹配请求两次。 “:

 "^/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 ,然后重新处理该请求。

为什么在第一次传递时,try文件不能为routing.php文件提供服务? 它存在并且可以访问,否则它不会在第二次服务。

编辑

删除了无关的configuration。

您明确引用的文档说“调用最后一个参数的内部redirect”。 内部redirect的处理方式与来自客户端的初始请求的处理方式相同 – 这包括在日志中看到的服务器级别处理rewrite语句。 但是,如果除最后一个之外的任何其他try_files参数与现有文件匹配,则使用try_files语句所在的locationconfiguration来处理该请求,并且不会有第二次匹配。

至于你的规则,你尝试只是在try_files省略$args

 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 ; 查询参数仍然会通过QUERY_STRINGparameter passing给FastCGI后端,这个参数大概是在你的fastcgi.conf设置的:

 fastcgi_param QUERY_STRING $query_string; 

如果$uri/routing.php都不作为文件存在,请求将被redirect到/50x_static.html并根据configuration文件中的location = /50x_static.html部分进行处理(但第二次重写尝试仍然会被执行,因为你的重写规则被放置在服务器级别)。

一个非常可疑的configuration细节是,无论文件扩展名如何,您都通过PHP传递所有文件 – 这是非常不寻常的,并且可能会导致安全问题,因为在不期望的文件中执行PHP代码。

谢尔盖说得对; 将$args添加到try_files命令会停止匹配文件,因此在另一个处理循环中发送Nginx,这很奇怪,因为这是Nginx 示例所要做的 。

如果您完全按照以下示例进行操作:

 try_files $uri $uri/ /index.php?q=$uri&$args; 

如果$uri$uri/不存在,那么Nginx将移到最后一个参数。 它甚至不尝试匹配文件,而是重新处理请求,将新path设置为/index.php $args现在为q=$uri&$args

另一方面,如果在index.php之后的try_files有另一个值,例如

 try_files $uri $uri/ /index.php?q=$uri&$args /50x_static.html; 

Nginx寻找一个名为/index.php?q=$uri&$args的文件,它显然不存在,所以它移动到/50x_static.html并重新处理。

因为$uri在Nginx重新处理请求时被重写,所以避免这个需要一些细微的改变。 如果你设置你的configuration是这样的:

 set $originalURI $uri; try_files $uri $uri/ /index.php /50x_static.html; fastcgi_param QUERY_STRING q=$originalURI&$query_string; 

Nginxfind的文件是/index.php ,这是正确的名字,所以nginx将停止处理。 我们必须复制$urivariables作为try_files修改它,所以它将只是/index.php如果我们只是在try_files后面使用它。