nginx的; 如果文件仅使用try_files存在,则返回响应代码

ser*_*ron 12 nginx

由于IfIsEvil我一直在尝试使用该指令设置配置,try_files以便维护页面与响应代码503一起显示,对于任何URI都没有例外,即包括php页面,如果存在维护文件.

我的配置有两个问题:

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

我已经看到类似的问题[1],[2]但没有一个try_files只使用(而不是使用if指令)的解决方案,并且如果存在相应的文件,则无条件地为响应代码503的维护页面提供服务.这样的解决方案是否可行?

以下是我目前的非工作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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想我的问题也可以这样说:可以try_files作为if控制结构吗?如果不是单独的话,是否可以将上述目标与其他指令结合起来,不包括if指令?

编辑:下面是使用if我正在使用的解决方案,将其包含在服务器部分:

error_page              503 @maintenance;

if (-f $document_root/maintenance.html) {
        return          503;
}

location @maintenance {
        try_files       /maintenance.html =404;
}
Run Code Online (Sandbox Code Playgroud)

Fle*_*der 9

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

只有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;
}
Run Code Online (Sandbox Code Playgroud)

这种方法有什么缺点吗?

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

其他方案?

通过nginx配置文件

为什么不创建一个nginx配置文件而只是重新加载进程,而不是创建一个HTML文件?

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

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

error_page 503 /maintenance.html;

location / {
  include maintenance.conf;
  if ($maintenance = 1) {
    return 503;
  }
  try_files $uri $uri/ /index.php?$args;
}
Run Code Online (Sandbox Code Playgroud)

maintenance.conf文件内容:

set $maintenance 0;
Run Code Online (Sandbox Code Playgroud)

如果要激活维护模式(在shell中):

echo set $maintenance 1;> maintenance.conf && service nginx reload
Run Code Online (Sandbox Code Playgroud)

对于shell朋友来说更高级 您甚至可以使用此扩展init脚本,例如通过替换文件末尾的以下块来兼容我的LSB:

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

使用以下块:

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
;;
Run Code Online (Sandbox Code Playgroud)

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

service nginx maintenance
Run Code Online (Sandbox Code Playgroud)

或者以下重新投入生产:

service nginx production
Run Code Online (Sandbox Code Playgroud)

使用脚本/ PHP文件

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

location / {
    try_files /maintenance.php $uri $uri/ /index.php?$args;
}
Run Code Online (Sandbox Code Playgroud)

您的PHP文件看起来与您的HTML文件完全相同,您只需在其开头添加以下内容(假设PHP为5.4+):

<?php http_response_code(503) ?><!doctype html>
<html>
<head>
<!-- ... more html ... -->
Run Code Online (Sandbox Code Playgroud)