Nginx - 将所有404错误传递回PHP-FPM以进行自定义错误页面处理

Luk*_*ins 9 php nginx http-status-code-404

我知道这已被问了一千次,但我找到的所有答案根本不起作用(对我来说或通常是这些问题的原始OP)......所以,我会试着解释这个问题我尽可能最好,希望我们可以让它为我和其他曾经问过的人工作.

我的Nginx配置(删除了许多其他不相关的东西)如下:

http {
    # Config from here removed

    server {
            listen 80;
            listen 443 ssl;
            server_name mydomain.co.uk;

            ssl_certificate /xxxxxxx.crt;
            ssl_certificate_key /xxxxxxx.key;

            # Custom error pages
            root /var/www/viovet_frontend;
            error_page 404 = /error404.php;

            # Any simple .php page
            location ~ \.php$ {
                    root /var/www/xxxxxx;
                    #index index.php index.html;

                    include /etc/nginx/fastcgi.conf;
                    fastcgi_pass phpfastcgiservers;
                    include fastcgi_params;

                    fastcgi_intercept_errors on;
            }

            # Lots more config and re-write rules here removed
    }

    upstream phpfastcgiservers {
            server xxxxx1:9001;
            server xxxxx2:9001;
            server xxxxx3:9001;
            fair;
    }
}
Run Code Online (Sandbox Code Playgroud)

我所要做的就是让Nginx捕获所有404并将它们发送回PHP-FPM,location ~ \.php$以便向用户显示一个自定义错误页面,但我总是得到标准的Nginx错误页面.

以下网址都应显示以下输出mydomain.co.uk/error404.php:

  • mydomain.co.uk/someNonExistantFile(与任何位置块都不匹配)
  • mydomain.co.uk/someMissingFile.php(匹配.php文件位置块但文件不存在)

但他们实际上显示了标准的Nginx 404页面.如果location ~ \.php$返回不同的错误代码到404(例如5xx),那么我们不想参与,只返回FastCGI首先返回的内容和标题.

我希望这是有道理的,有人可以提供帮助.先感谢您.

编辑:我尝试添加recursive_error_pages on;到该行后,# Custom error pages但这实际上导致所有Nginx 404 Not Found错误成为Nginx 500 Internal Server Error错误.

编辑:添加其他文件: /etc/nginx/fastcgi.conf

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;
Run Code Online (Sandbox Code Playgroud)

fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;
Run Code Online (Sandbox Code Playgroud)

我想我可能不需要这两个!;-)

Luk*_*ins 14

我终于完成了大部分工作.感谢大家提供的建议并花时间写答案.

问题是我们error404.php正在返回带有404 Not Found标头的错误页面(使用header('HTTP/1.0 404 Not Found');),然后Nginx拦截了这个错误,因为它recursive_error_pages是关闭的(默认)并且它显示了它自己的404页面.关闭fastcgi_intercept_errors是解决方案.如果我们header('HTTP/1.0 404 Not Found');从错误文件中删除,那么我们会得到错误,但200显然不是我们想要的错误.

然而,这并没有解决访问以页面结尾的缺失页面的问题.php(因此它与位置块匹配,因为我们现在正在回复标准的PHP-FPM响应到404标题的主体File not found..我可以使用Nate的回答解决这个问题,但我不想在那里指定所有的文件名.我会寻找另一个解决方案,并在我得到一个时将其发布在这里.

编辑:一个更完整的解决方案:

您需要拦截主php位置块(fastcgi_intercept_errorson)中的错误,然后为您的错误页面设置另一个块,您不会拦截它们.请参阅此配置示例:

    server {
            listen 80;
            listen 443 ssl;
            server_name mydomain.co.uk;

            ssl_certificate /xxxxxxx.crt;
            ssl_certificate_key /xxxxxxx.key;

            # Custom error pages
            recursive_error_pages off;
            error_page 404 = /http_errors/404.php;
            # error_page 500 501 502 503 504 = /error5xx.php; # Not sure about this yet!

            # Any simple .php page
            location ~ \.php$ {
                    root /var/www/xxxxx;

                    include /etc/nginx/fastcgi.conf;
                    fastcgi_pass phpfastcgiservers;
                    include fastcgi_params;

                    fastcgi_intercept_errors on;
            }

            # Handling error pages
            location ^~ /http_errors/ {
                    internal;

                    root /var/www/xxxxx;

                    include /etc/nginx/fastcgi.conf;
                    fastcgi_pass phpfastcgiservers;
                    include fastcgi_params;

                    fastcgi_intercept_errors off;
            }
}
Run Code Online (Sandbox Code Playgroud)

这意味着返回HTTP状态代码为404的任何PHP页面都将忽略其自己的内容(如果有),并且/http_errors/404.php将使用您的文件内容.