ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

APISIX 调试功能:利用 `X-APISIX-Upstream-Status` 响应头定位 `5xx` 状态码来源

2026/9/21 18:50:49 拓冰建站 浏览量
APISIX 调试功能:利用 `X-APISIX-Upstream-Status` 响应头定位 `5xx` 状态码来源 APISIX 调试功能利用X-APISIX-Upstream-Status响应头定位5xx状态码来源【免费下载链接】apisixThe Cloud-Native API Gateway and AI Gateway项目地址: https://gitcode.com/gh_mirrors/api/apisix本文基于 Apache APISIX 源码仓库中 docs/zh/latest/debug-function.md 展开讲解当网关返回5xx状态码时如何通过响应头快速判断错误是来自 APISIX 自身还是来自 Upstream上游服务并深入剖析该响应头在 apisix/init.lua 中的实现原理。读完本文你将掌握X-APISIX-Upstream-Status的判定规则、show_upstream_status_in_response_header配置项的作用以及多节点重试场景下响应头的取值逻辑从而在日常排障中一眼定位问题环节。5xx状态码的来源辨析500、502、503等5xx状态码是服务器错误类响应码。在 APISIX 作为网关的链路中一次请求出现5xx时错误可能来源于两个不同的环节Upstream上游服务上游业务服务本身出错、连接被拒绝、连接超时等网关将上游返回的错误透传给客户端APISIX网关自身路由匹配失败、插件执行出错、网关内部异常等由 APISIX 直接构造错误响应返回客户端。两者在客户端看到的最终状态码可能完全相同例如都是502因此仅凭状态码无法区分错误来源。此时X-APISIX-Upstream-Status响应头就是最直接的判别依据。核心判定规则X-APISIX-Upstream-Status判定规则非常简洁当5xx状态码来源于 Upstream时响应头中会出现X-APISIX-Upstream-Status且其值即为上游返回的状态码当5xx状态码来源于 APISIX时响应头中没有X-APISIX-Upstream-Status。即X-APISIX-Upstream-Status响应头的存在与否直接反映了上游是否参与产生该错误。注意该行为受配置项show_upstream_status_in_response_header控制。将其修改为true后APISIX 会返回所有上游状态码包括200、404等非5xx而不仅仅是5xx保持默认值false时则只有上游返回5xx才会写入该响应头。配置项详解show_upstream_status_in_response_header该配置位于conf/config.yaml的apisix段下默认值为false。参考仓库中 conf/config.yaml.example 的注释说明apisix: show_upstream_status_in_response_header: false # If true, include the upstream HTTP status code in # the response header X-APISIX-Upstream-Status. # If false, show X-APISIX-Upstream-Status only if # the upstream response code is 5xx.默认值的定义可以在 apisix/cli/config.lua 中看到local _M { apisix { ... show_upstream_status_in_response_header false,配置修改后需要重启或 reload APISIX 使其生效。实现原理header_filter 阶段的响应头写入从源码层面看该响应头的写入逻辑位于 apisix/init.lua 的http_header_filter_phase函数中。在 Nginx 的header_filter阶段APISIX 会先读取 Nginx 内置变量upstream_status该变量记录了一次请求访问上游的完整状态码序列然后调用set_resp_upstream_status决定是否写入响应头function _M.http_header_filter_phase() ... local up_status get_var(upstream_status) if up_status then set_resp_upstream_status(up_status) end ... end核心判定函数set_resp_upstream_statusapisix/init.lua完整实现了上述规则local function set_resp_upstream_status(up_status) local_conf core.config.local_conf() if local_conf.apisix and local_conf.apisix.show_upstream_status_in_response_header then core.response.set_header(X-APISIX-Upstream-Status, up_status) elseif #up_status 3 then if tonumber(up_status) 500 and tonumber(up_status) 599 then core.response.set_header(X-APISIX-Upstream-Status, up_status) end elseif #up_status 3 then -- the up_status can be 502, 502 or 502, 502 : local last_status if str_byte(up_status, -1) str_byte( ) then last_status str_sub(up_status, -6, -3) else last_status str_sub(up_status, -3) end if tonumber(last_status) 500 and tonumber(last_status) 599 then core.response.set_header(X-APISIX-Upstream-Status, up_status) end end end这段代码揭示了三条关键行为开启全量上报当show_upstream_status_in_response_header为true时无条件写入响应头无论上游状态码是多少默认仅上报5xx当up_status长度为 3即单次请求、单个状态码如502时只有落在500~599区间才写入多节点重试场景当up_status长度大于 3即发生过重试形如502, 502, 502或带尾随空格的502, 502, 502 :时会解析最后一个状态码判断是否为5xx若为5xx则把完整的重试状态码序列写入响应头——这意味着你可以看到每次重试的真实结果。实战示例以下示例均以 APISIX 默认端口Admin API9180、网关9080为例。可以从conf/config.yaml中提取admin_key存入环境变量admin_key$(yq .deployment.admin.admin_key[0].key conf/config.yaml | sed s///g)示例 1502来源于 UpstreamIP 地址不可用创建一个指向不可用节点127.0.0.1:1的路由$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H X-API-KEY: $admin_key -X PUT -d { methods: [GET], upstream: { nodes: { 127.0.0.1:1: 1 }, type: roundrobin }, uri: /hello }请求验证$ curl http://127.0.0.1:9080/hello -v ...... HTTP/1.1 502 Bad Gateway Date: Wed, 25 Nov 2020 14:40:22 GMT Content-Type: text/html; charsetutf-8 Content-Length: 154 Connection: keep-alive Server: APISIX/2.0 X-APISIX-Upstream-Status: 502 html headtitle502 Bad Gateway/title/head body centerh1502 Bad Gateway/h1/center hrcenteropenresty/center /body /html响应头中存在X-APISIX-Upstream-Status: 502说明该502是由上游连接失败触发的错误来源于 Upstream。示例 2502来源于 APISIX插件注入错误通过fault-injection插件让 APISIX 直接返回500$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H X-API-KEY: $admin_key -X PUT -d { plugins: { fault-injection: { abort: { http_status: 500, body: Fault Injection!\n } } }, uri: /hello }请求验证$ curl http://127.0.0.1:9080/hello -v ...... HTTP/1.1 500 Internal Server Error Date: Wed, 25 Nov 2020 14:50:20 GMT Content-Type: text/plain; charsetutf-8 Transfer-Encoding: chunked Connection: keep-alive Server: APISIX/2.0 Fault Injection!响应头中没有X-APISIX-Upstream-Status说明该错误由 APISIX 自身产生与上游无关。示例 3Upstream 多节点全部不可用重试场景创建包含三个不可用节点、重试次数为 2 的 Upstream并绑定到路由$ curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -H X-API-KEY: $admin_key -X PUT -d { nodes: { 127.0.0.3:1: 1, 127.0.0.2:1: 1, 127.0.0.1:1: 1 }, retries: 2, type: roundrobin }$ curl http://127.0.0.1:9180/apisix/admin/routes/1 -H X-API-KEY: $admin_key -X PUT -d { uri: /hello, upstream_id: 1 }请求验证$ curl http://127.0.0.1:9080/hello -v HTTP/1.1 502 Bad Gateway Date: Wed, 25 Nov 2020 15:07:34 GMT Content-Type: text/html; charsetutf-8 Content-Length: 154 Connection: keep-alive Server: APISIX/2.0 X-APISIX-Upstream-Status: 502, 502, 502 html headtitle502 Bad Gateway/title/head body centerh1502 Bad Gateway/h1/center hrcenteropenresty/center /body /html响应头为X-APISIX-Upstream-Status: 502, 502, 502清楚地展示了对三个节点依次重试且全部失败的过程——这正是set_resp_upstream_status中#up_status 3分支所处理的场景。测试用例佐证仓库中的测试文件 t/node/upstream-status-all.t 对该功能进行了全面覆盖可作为理解与复现的参考TEST 2上游返回200时开启配置后响应头为X-APISIX-Upstream-Status: 200验证全量上报TEST 4上游读超时返回504响应头为X-APISIX-Upstream-Status: 504TEST 6上游连接被拒Connection refused返回502响应头为X-APISIX-Upstream-Status: 502TEST 11一个节点失败一个节点成功响应头为X-APISIX-Upstream-Status: 502, 200验证重试状态序列TEST 13三个节点全部失败响应头为X-APISIX-Upstream-Status: 502, 502, 502TEST 15/17/19由 fault-injection 插件从 APISIX 侧返回500、200时开启配置后响应头体现的是注入状态码TEST 19 在关闭配置时200不会写入响应头验证false时仅5xx上报。这些用例与上文源码逻辑一一对应读者可结合 t/node/upstream-status-all.t 深入理解各分支行为。排障实践小结场景响应头特征结论上游返回5xx默认配置存在X-APISIX-Upstream-Status: 5xx错误来源于 UpstreamAPISIX 自身返回5xx默认配置无X-APISIX-Upstream-Status错误来源于 APISIX多节点重试且最终失败X-APISIX-Upstream-Status: 502, 502, 502可查看每次重试的状态码序列开启show_upstream_status_in_response_header: true始终存在响应头任意状态码可观测所有上游状态码在实际排障中建议优先查看该响应头判断错误来源再结合 APISIX 错误日志如Connection refused、Connection timed out等进一步定位上游节点问题若响应头缺失而状态码为5xx则应聚焦于 APISIX 自身的路由、插件与内部逻辑。相关英文文档见 docs/en/latest/debug-function.md配置默认值见 apisix/cli/config.lua完整配置示例见 conf/config.yaml.example。【免费下载链接】apisixThe Cloud-Native API Gateway and AI Gateway项目地址: https://gitcode.com/gh_mirrors/api/apisix创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考