这个问题早就应该回答了,但尽管阅读了许多常见答案,我似乎还是无法弄清楚,有人可以指出为什么我的配置不起作用吗?
目标:当上游 server_api 关闭(比如,它的工作进程崩溃了)时,我希望 nginx 显示我的自定义错误页面。
我的配置:
location @server {
proxy_pass http://server_api;
proxy_redirect off;
...
proxy_intercept_errors on;
error_page 502 /error-502.html;
}
error_page 502 /error-502.html;
location = /error-502.html {
internal;
root /srv/my-server/html;
}
我的步骤:
- 我已经准备好了静态错误页面
/srv/my-server/html/error-502.html
,具有与其他静态资产相同的权限和所有者。 - 我已经停止了我的上游服务,并
[error] 2359#0: *25 connect() failed (111: Connection refused) while connecting to upstream
在日志中看到出现。 - 现在我尝试让我的自定义错误页面显示 502 错误。
- 我已尝试设置
error_page
两者或任一server
或location
块。 - 我已经尝试在或块中
error_page
使用;proxy_intercept_errors on
location
server
它们似乎都无法说服 nginx 显示我的错误页面。为什么不行?我错过了什么?
答案1
感谢 Justin 和 Michael 为我指明了正确的方向,确实是位置阻塞导致了我的麻烦,特别是:
location / {
try_files $uri $uri/ @server;
error_page 403 = @server;
}
基本上,我试图变得聪明并捕捉$uri/
错误(当您尝试访问存在但没有索引文件或自动索引的文件夹时会发生 403)并将其重定向到@server
阻止。
但try_files $uri $uri/ @server;
独自一人还不够吗?
想象一下你试图访问http://example.com/
,nginx 会说,哦,这个文件夹存在(它是你的root
),但是没有找到索引,并且抛出 403 而不是传递给@server
块。
因此我的解决方案是 403,但我没有意识到它是有代价的:这意味着 nginx 已经捕获到一个错误并error_page
在同一个location
块中用来处理它(通过将其传递给@server
)。
将此与我在问题中的测试结合起来,它表明 nginx(v1.7.x)将忽略error_page
此时的进一步指令并改用默认的 502。
有趣的是:我们该如何解决这个问题?
我的解决方案是设置一个完全匹配的根路由,现在不再需要在根路由上捕获 403,并且可以error_page
按预期工作。
error_page 502 /error-502.html;
location = /error-502.html {
internal;
root /srv/example.com/html;
}
location = / {
try_files $uri @server;
}
location / {
try_files $uri $uri/ @server;
}
答案2
如果不查看您的整个配置,很难确定,因为对我来说,即使没有您采取任何额外措施,这个配置也能正常工作。我首先尝试了您的所有配置,然后逐一删除一些配置,看看是否有任何变化。
没有必要使用 proxy_intercept_errors,因为当 nginx 无法连接到后端时,它自己会生成 502。我确认,设置和取消设置后,这对我有用。
我在服务器块中添加的所有内容是:
error_page 502 /error-502.html;
location = /error-502.html {
internal;
root /srv/www/errors;
}
在我的设置中,我的静态错误页面位于 /srv/www/errors,但其他方面没有什么不同。
您必须在服务器范围或服务器块中的其他地方进行配置,这些配置会干扰或覆盖。请注意位置的优先规则,这可能是一个因素。