nginx的; 如果文件只存在于try_files中,则返回响应码

由于IfIsEvil我一直试图build立一个configuration使用指令try_files只有一个维护页面与响应代码503一起显示,任何URI没有例外,即包括PHP页面,如果维护文件存在。

我的configuration有两个问题:

  1. 维护页面不显示php URI。
  2. 如果maintenance.html文件存在,则不返回响应代码503。

我见过类似的问题[1] , [2],但没有一个只使用try_files的解决scheme(与使用if指令相反),并且无条件地为响应代码503提供维护页面,如果存在相应的文件。 这样的解决scheme可能吗?

下面是我目前的非工作conf文件。 它不包含503响应代码设置,因为我不明白为了使它如上所述工作应该在哪里。

 worker_processes 1; error_log /var/log/nginx/error.log debug; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; index index.php index.html index.htm; server { listen 80; server_name rpi; root /www; location / { try_files /maintenance.html $uri $uri/ /index.php?$args; # pass the PHP scripts to FastCGI server location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; include fastcgi.conf; } } } } 

我想我的问题也可以这样表述: try_files可以作为一个if控制结构吗? 如果不是这样,那么,为了达到上述目标,是否可以将其与其他指令结合起来,排除if指令?

编辑:下面是一个解决scheme, if我正在使用,通过将其包含在服务器部分:

 error_page 503 @maintenance; if (-f $document_root/maintenance.html) { return 503; } location @maintenance { try_files /maintenance.html =404; } 

非常好的问题! 但是,除非您调用某种设置正确响应代码的脚本,否则根本不可能。

只有nginx的工作解决方案,如果没有

try_files指令仅对最后一条语句执行内部重定向。 但是我们可以将它与index指令结合起来并强制内部重定向。

 # This will be the HTML file to display for the 503 error. error_page 503 /maintenance/maintenance.html; # Let nginx know that this particular file is only for internal redirects. location = /maintenance/maintenance.html { internal; } # Any request that starts with the maintenance folder is 503! location ^~ /maintenance/ { return 503; } # Instead of checking if a file exists and directly delivering it we check # if a certain directory exists and trigger our index directive which will # perform an internal redirect for us. location / { expires epoch; try_files /maintenance/ $uri $uri/ /index.php?$args; } 

这种方法有什么缺点?

  • 实际301重定向到目录,而不是停留在相同的URL(搜索引擎)。
  • 浏览器缓存301重定向可能是一个问题,这就是为什么我添加了expires epoch到位置块。

其他解决方案

通过nginx配置文件

为了不创建一个HTML文件,为什么不创建一个nginx配置文件,并简单地重新加载进程?

  • 性能更好!
  • 更容易理解!
  • 无副作用!

nginx的配置可能如下所示(注意, if不是邪恶的话):

 error_page 503 /maintenance.html; location / { include maintenance.conf; if ($maintenance = 1) { return 503; } try_files $uri $uri/ /index.php?$args; } 

maintenance.conf文件的内容:

 set $maintenance 0; 

如果你想激活维护模式(在你的shell中):

 echo set $maintenance 1;> maintenance.conf && service nginx reload 

更高级的外壳朋友你甚至可以用这个扩展一个初始化脚本,例如我的LSB兼容的替换下面的块在文件的末尾:

 *) echo "Usage: ${NAME} {force-reload|reload|restart|start|status|stop}" >&2 exit 1 ;; 

用以下块:

 maintenance) echo "set $maintenance 1;" > /etc/nginx/maintenance.conf && service nginx reload; ;; production) echo "set $maintenance 0;" > /etc/nginx/maintenance.conf && service nginx reload; ;; *) echo "Usage: ${NAME} {force-reload|reload|restart|start|status|stop|maintenance|production}" >&2 exit 1 ;; 

现在您可以简单地执行以下命令(包括自动完成)进入维护模式:

 service nginx maintenance 

或者下面重新投入生产:

 service nginx production 

用脚本/ PHP文件

另一个非常简单的方法就是使用一个处理它的PHP文件。

 location / { try_files /maintenance.php $uri $uri/ /index.php?$args; } 

你的PHP文件看起来和你的HTML文件完全一样,你只需要添加以下内容(假设PHP 5.4+):

 <?php http_response_code(503) ?><!doctype html> <html> <head> <!-- ... more html ... -->