财务管理-结算记录:点「查询」偶发 502(Request failed with status code 502)

Status: needs-triage
领域: 支付链路(自动结算与结算记录)+ 管理后台公共 http 客户端
来源: 用户工单「【结算记录】查询报错了 这个是什么问题 现在无法重现」(截图:2026-09-18 页面顶部红色提示 Request failed with status code 502,表格里仍是上一次查询出来的数据)
日期: 2026-09-18

现象

「财务管理 → 结算记录」点「查询」时,页面顶部弹出红色提示 Request failed with status code 502。
列表本身已经渲染出数据(说明**上一次**查询是成功的),失败的是**这一次**请求。用户随后重试无法复现。

根因

这个 502 不是结算记录接口自己返回的,而是「前端 → 后端」之间代理层的报错:代理向上游发起请求时
连接出错(后端不在监听 / 连接被中途重置),Vite 的代理中间件就固定回一个 502 + 空 body。

三处证据:

  1. 文案只可能来自这里:talent-card-admin/src/api/http.ts:36-38 的提示是
    error.response?.data?.message || error.message。后端所有业务异常都会带 JSON {code, message},
    只有响应体里没有 message(例如代理回的 502 空 body)时才会退化成 axios 兜底文案
    Request failed with status code 502。
  2. Vite 代理正好是 502 + 空 body:talent-card-admin/node_modules/vite/dist/node/chunks/node.js:18674-18681
    —— proxy.on('error', ...) { ... res.writeHead(502, { 'Content-Type': 'text/plain' }).end() };
    同时终端里会打一行 http proxy error: /api/... 加 err.stack。
  3. 后端代码里没有 502:talent-card-server 的 java 与 resources 全量搜索无 502/Bad Gateway,
    接口出错走的是 Bean Validation / BusinessException(JSON 响应),不会产生代理级状态码。

所以「无法重现」是预期的:触发条件是**那一瞬间的连接失败**,常见来源——

  • 后端正好在重启(IDEA 里重新运行 / mvn 重新编译部署),端口有一段不可连接的空窗;
  • 代理复用了 Tomcat 已经关掉的 keep-alive 长连接,Vite 侧收到 RST 后直接把这次请求判成 502;
  • 后端进程被重启/挂起,请求在写响应前连接就断了。

关联的稳定性隐患(同一个接口,值得一并处理)

结算记录这条链路本身很"重",商户一多就更容易撞上上面任何一种超时/重试:

  • MerchantSettlementAdminService.settlements(...)
    (talent-card-server/src/main/java/com/talentcard/server/business/admin/MerchantSettlementAdminService.java:68-83)
    是**逐商户串行**调用斗拱结算流水接口:for (merchant : merchants) settlementRecordGateway.query(...),
    没有并发、没有超时上限、没有缓存。单次「查询」的成本 = 已进件商户数 × 一次跨公网 HTTPS 往返。
  • 当前库里符合条件的商户(status='approved' 且 provider_huifu_id 非空的每个商户最新一条)是 4 家:
    喜望商家 6666000239896857、存量商户验证专用 6666000226048687、个人进件验证商户 6666001804122、
    景区服务-卡 6666000242182522。商户继续变多,整页耗时线性增长。
  • 前端 axios 只等 12 秒(talent-card-admin/src/api/http.ts:9 timeout: 12000),一旦超过就是
    timeout of 12000ms exceeded(另一个不同的报错文案),或用户以为"卡住了"而重复点击、放大后端压力。
  • 后端**没有文件日志**(application.yml:164-166 只配了 logging.level,没有 file appender),
    所以事后查不到当时的 Huifu settlement record query failed / 请求耗时——这也是这次"查无实据"的原因之一。

建议改法(支付链路负责人 / 前端公共部分)

  1. 先按现场日志定性:复现时看 Vite 终端有没有 http proxy error: /api/admin/management/merchant-settlement/settlements
    (有 = 连接层问题,看 err.stack 区分 ECONNREFUSED / ECONNRESET)、**IDEA 控制台**在那个时间点是否在重启。
  2. 结算记录接口收敛耗时:商户维度并发查询(或限流并发)+ 单商户调用超时上限 + 结果短时缓存/手动刷新,
    让整页耗时不再随商户数线性增长。
  3. 后端加文件日志(或至少把通道查询耗时记进日志),下次出现同类问题能直接判断是"慢"还是"断"。
  4. 前端错误提示区分"代理/网关错误"与业务错误:对 502/504/ECONNABORTED 给出中文提示,
    而不是把 axios 的英文兜底文案直接弹给用户。

Comments

  • 2026-09-18:由「其余业务」侧的会话只读排查后归档(按仓库约定,支付链路代码未改动)。
    结论:本次 502 是**代理层**的连接失败(后端重启/长连接被重置),不是结算记录接口的业务缺陷;
    但该接口「逐商户串行查斗拱 + 前端 12 秒超时 + 无文件日志」让它天然容易出现这类偶发失败,建议一并收敛。