php 中的 nginx 404 处理程序忽略 HTTP 状态

php 中的 nginx 404 处理程序忽略 HTTP 状态

这是在 CentOS 7.2 中通过 PHP-FPM 使用 nginx 1.6.3 和 PHP 7.0.7。

我使用 LAMP 运行过许多网站,并一直在尝试切换到 LEMP,但不断出现的一个症结是,尽管我在 PHP 中设置了不同的状态,但我的页面处理程序状态中始终显示 404 错误。就好像 nginx 完全忽略了 PHP 发送的 404 错误页面的标头。

/etc/nginx/nginx.conf 看起来像:

user web web;
worker_processes auto;
error_log /var/web/Logs/WebServer/nginx-error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/web/Logs/WebServer/nginx-access.log  main;

    fastcgi_buffers 8 1024k;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
}

每个域的配置如下:

server {
    listen       80;
    server_name  www.something.com;

    root /var/web/www.something.com/;
    index index.php index.html;

    error_page 404 /PageHandler;

    location / {
        try_files $uri $uri/ /PageHandler =404;
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
            fastcgi_index index.php;
            include fastcgi.conf;
        }
        location /PageHandler {
            try_files /PageHandler.php =500;
            fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
            include fastcgi.conf;
            fastcgi_param REDIRECT_STATUS 404;
        }
    }
}

非常简单的 PHP 脚本是(是的,我知道标题是多余的,但它仍然什么也不做):

<?php
  http_response_code(200);
  header("HTTP/1.1 200 OK");
  header("Status: 200", true, 200);
?>
Test <?= $_SERVER["REQUEST_URI"] ?>, code <?= $_SERVER["REDIRECT_STATUS"] ?>

我花了几个小时徒劳地寻找如何修复此问题。我尝试了至少一百种不同的 .conf 格式,但都不起作用。我上面的方法至少将 REDIRECT_STATUS 设置为 404,但如果找到页面,我发现没有办法返回 200 状态代码。我不能让 nginx 始终返回 200,因为它实际上可能是真正的 404,因为实际脚本会在数据库中测试当前 URL。

如何让 nginx 遵守 PHP 的 HTTP 状态标头?

答案1

对我来说,这些嵌套location块看起来很麻烦,而且没有必要。试试这个:

server {
    listen       80;
    server_name  www.something.com;

    root /var/web/www.something.com/;
    index index.php index.html;

    try_files $uri $uri/ /PageHandler.php =404;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }
}

答案2

显而易见的做法是删除它:

    error_page 404 /PageHandler;

它完全是多余的,因为任何未找到的静态文件路径都会被你的第一个文件指向那里try_files。它只是用来error_page提供服务的必要或有用的东西静止的错误页面。

答案3

通过结合我从多次失败中吸取的教训、我收到的另外两个答案(感谢 Michael Hampton 和 Tero Kilkanen 为我指明了正确的方向)以及进一步研究 try_files 的直觉,我发现问题集中在 try_files 在我的安装中的工作方式上。这里有更多详细信息: try_files 如何工作? 和这里: http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files

最终的工作服务器配置是:

server {
    listen       80;
    server_name  www.something.com;

    root /var/web/www.something.com/;
    index index.php index.html;

    try_files $uri $uri/ @PageHandler;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi.conf;
    }

    location @PageHandler {
        try_files /PageHandler.php =404;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        include fastcgi.conf;
        fastcgi_param REDIRECT_STATUS 404;
    }
}

如您所见,我使用了 @PageHandler 的命名位置并将其绑定。它使用默认 HTTP 状态 200 而不是 404,但由于我可以从 PHP 控制它,因此我在必要时将其明确设置为 404。

使用以下任何一个 PHP 命令都会改变我的浏览器所看到的状态(所有三个命令都不是必需的):

http_response_code(404);
header("HTTP/1.1 404 Not Found");
header("Status: 404", true, 404);

相关内容