从 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
)的内容。我的考虑是:
- 当在
new-app
中请求一个不存在的 URL 时,我们想看看 old-app
是否有它的内容,所以 new-app
抛出一个 404
- Nginx 捕获此 404 并将请求代理到
old-app
- 当
old-app
中有内容时,它应该与 2xx/3xx 响应代码一起提供
- 如果
old-app
中也没有内容,则抛出额外的 404
- 这个 404 应该被 Nginx 再次捕获并且应该在
new-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;
}
}
我在 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
)的内容。我的考虑是:
- 当在
new-app
中请求一个不存在的 URL 时,我们想看看old-app
是否有它的内容,所以new-app
抛出一个 404 - Nginx 捕获此 404 并将请求代理到
old-app
- 当
old-app
中有内容时,它应该与 2xx/3xx 响应代码一起提供 - 如果
old-app
中也没有内容,则抛出额外的 404 - 这个 404 应该被 Nginx 再次捕获并且应该在
new-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;
}
}