proxy_intercept_errors 是 Nginx 代理中启用后端错误响应拦截的开关,仅对 proxy_pass 流量中状态码 ≥300 且含合法 HTTP 头部的响应生效(如 404、502、504),不拦截 Nginx 自身生成的错误或 3xx 重定向;必须与同作用域的 error_page 指令配合使用才生效,本身不生成页面,仅控制是否交由 error_page 处理。

proxy_intercept_errors 是什么,它能拦截哪些错误
proxy_intercept_errors 不是“自动重写错误响应”,而是让 Nginx 在收到后端返回的 4xx/5xx 响应时,**放弃直接透传给客户端**,转而检查是否配置了对应状态码的 error_page 指令。它本身不生成页面,只开启“拦截开关”。
必须配合 error_page 才生效;默认值为 off,即所有后端错误原样返回——这也是你看到裸 502/504 的根本原因。
- 仅对 proxy_pass 流量生效(不作用于静态文件或 fastcgi)
- 只拦截后端明确返回的状态码(如 PHP-FPM crash 返回 502、上游超时返回 504),不拦截 Nginx 自己产生的 502(比如 upstream 定义错误)
- 若后端返回 502 但未设置
error_page 502,即使开了proxy_intercept_errors on,Nginx 仍会透传 502
如何正确配置 502/504 降级页(含路径与 MIME 处理)
关键不是打开 proxy_intercept_errors,而是让它和 error_page、location 形成闭环。常见错误是把降级页放在 root 下却没配对的 location 块来服务它。
示例配置片段:
⚠️ 已弃用 — 该技能已拆分为两个独立技能,以提升模块化程度:**webchat-https-proxy**(HTTPS/WSS 反向代理)和 **webchat-voi...**
location / {
proxy_pass http://backend;
proxy_intercept_errors on;
error_page 502 504 /fallback.html;
}
<p>location = /fallback.html {
root /usr/share/nginx/html;
internal; # 防止用户直接访问该页
}</p>
-
error_page 502 504 /fallback.html中的路径是 URI,不是文件系统路径,所以必须有对应location去处理这个 URI -
root在location = /fallback.html内定义,意味着实际文件路径是/usr/share/nginx/html/fallback.html - 务必加
internal:否则用户 curl http://domain/fallback.html 就能绕过业务直接看到降级页 - 确保
fallback.html文件存在且 Nginx 有读取权限,否则会返回 500(此时又需要额外配error_page 500,形成嵌套)
为什么开了 proxy_intercept_errors 还是透传 502?排查三步法
最常踩的坑不是配置错,而是没意识到 Nginx 的错误处理有优先级和范围限制。
-
检查 upstream 是否真返回了 502:用
curl -v http://upstream-ip:port直连后端,确认它确实返回 502(而非连接拒绝导致 Nginx 自己生成 502) -
确认 error_page 在 proxy_pass 同一 location 块内:如果写在 server 级或外层 location,可能不生效;Nginx 的
error_page是局部指令,作用域严格 -
检查是否有更早匹配的 location 拦截了 error_page 的 URI:比如你配了
location / { ... }和location /fallback.html,但同时存在location ^~ /fallback,后者会优先匹配并可能没加internal,导致降级失败
降级页里怎么保留原始 URL 和错误信息(可选增强)
Nginx 原生不向降级页传递原始请求上下文,但可以通过 add_header + 前端 JS 或简单服务端渲染实现基础反馈。
- 在主 location 中添加:
add_header X-Original-URI $request_uri;和add_header X-Error-Status $status;(注意:$status 是 Nginx 当前响应状态,对降级页而言是 200,需改用$upstream_http_x_error_status等自定义头,前提是后端主动输出) - 更可靠的做法:让后端在返回 502/504 时,通过
add_header注入自定义头(如X-Backend-Error: timeout),再在error_page对应的 location 中用proxy_pass转发到一个轻量 fallback service,由它读取 header 渲染带上下文的页面 - 纯静态 fallback.html 无法动态显示原始 URL,除非用 JS 读
window.location.referrer(不可靠)或服务端做一次重定向(增加延迟)
真正难的不是配出降级页,而是确保它只在该触发时触发、不被绕过、不掩盖真实故障——比如后端持续 504,但降级页缓存了,运维就看不到告警了。










