从 Nginx 中的多个代理请求中捕获 404

Catch 404 from multiple proxied requests in Nginx

我在 Debian Jessie 上使用 Nginx 1.10.3 运行 具有以下设置的自部署应用程序。

负载均衡器配置:

upstream www {
    server [fda4::0:21]:8080 weight=80;
    server [fda4::0:22]:8080 weight=100;
    keepalive 100;
}
server {
    listen 80;
    server_name example.com;
    location / {
        rewrite ^/(.+)/+$ / permanent;
        include /etc/nginx/proxy_params;
        proxy_set_header X-Forwarded-Host $host;
        proxy_pass http://www;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    }
}

后端配置:

server {
    listen [::]:8080 default_server backlog=1024;
    root /var/www/$host/web;
    index index.php;

    try_files $uri /index.php?$query_string;
    location ~ ^/index\.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_read_timeout 60s;
    }
}

我们有一个基于此设置的项目 new-app,在迁移完成之前,应提供来自旧 CMS(称为 old-app)的内容。我的考虑是:

这可以用 Nginx 完成吗?我认为

proxy_intercept_errors on;
error_page 404 = @404;
location @404 {
    proxy_pass http://old-app.domain;
}

有人可以做到这一点,但是当 old-app 也抛出 404 时,这不会启动无限循环的 catch-and-proxy 吗?在 old-app 后端捕获 404 以提供静态错误页面的干净解决方案是什么样的?

如果您总是想先 new-app 服务器,除非出现错误,您可以使用两个位置块来做到这一点:

upstream new-app {
    server [fda4::0:21]:8080 weight=80;
    server [fda4::0:22]:8080 weight=100;
    keepalive 100;
}

upstream old-app {
    server [fda4::0:21]:8081 weight=80;
    server [fda4::0:22]:8081 weight=100;
    keepalive 100;
}

server {
    listen 80;
    server_name example.com;
    recursive_error_pages on;

    location @old-app {
        rewrite ^/(.+)/+$ / permanent;
        include /etc/nginx/proxy_params;
        proxy_set_header X-Forwarded-Host $host;
        proxy_pass http://old-app;
    }

    location / {
        rewrite ^/(.+)/+$ / permanent;
        include /etc/nginx/proxy_params;
        proxy_set_header X-Forwarded-Host $host;
        proxy_pass http://new-app;
        proxy_intercept_errors on;
        error_page 404 = @old-app;
    }
}