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

标签 nginx

IfIsEvil我一直在尝试使用指令 try_files 设置配置只是为了使维护页面与响应代码 503 一起显示,对于任何 URI,如果存在维护文件,则无一异常(exception),即包括 php 页面。

我的配置有两个问题:

  • 维护页面不会显示 php URI。
  • 如果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;
                }
            }
        }
    }
    

    我想我的问题也可以这样表述:Can try_files可以作为 if 工作控制结构?如果不是单独使用,是否可以根据上述目标与其他指令结合使用,不包括 if指示?

    编辑:以下是使用 if 的解决方案我目前正在使用的方法是将其包含在服务器部分中:
    error_page              503 @maintenance;
    
    if (-f $document_root/maintenance.html) {
            return          503;
    }
    
    location @maintenance {
            try_files       /maintenance.html =404;
    }
    

    最佳答案

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

    仅适用于 nginx 而没有 if 的有效解决方案

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

    # 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
    

    shell 友更进阶
    您甚至可以使用此扩展初始化脚本,例如 my LSB compliant one通过替换文件末尾的以下块:
    *)
      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 ... -->
    

    关于nginx;如果文件存在,则仅使用 try_files 返回响应代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16693209/

    相关文章:

    configuration - nginx - 是否有用于编辑配置文件的 CLI 工具?

    ssl - nginx 与 ssl 编译错误

    根据请求的来源将反向代理重定向到 SSL

    cakephp - Nginx 上游在从上游读取响应 header 时发送了太大的 header

    mysql - 使用 nginx 服务器和 AWS RDS 的 Laravel 出现 "too many connections"错误

    docker - 502 Bad Gateway nginx/1.13.12 on localhost 同时在同上创建新策略

    php - 为什么 opcache 没有被刷新?

    nginx - 如何在 nginx 中禁用 TLS 重新协商

    laravel - laravel 中的 Illuminate\Http\Exceptions\PostTooLargeException

    regex - nginx URL 重写使用负正则表达式?