hl-api-changelog/changelogs/2026-04/28_fix_order_contract-tourage-api-exception-classify.md
API Changelog Bot 4d8ab772f3 docs: 12301 合同 API 异常分类细化 PR #1520 / 工单 #1518
- 网络/5xx 走兜底重试(ResourceAccessException + HttpStatusCode 5xx → RuntimeException)
- 4xx 保留原 errorNode 返回行为(不破坏 isSuccess+getErrorMessage 调用方 + 保留审计 rawResponse)
- 单测新增 7 用例覆盖网络/4xx/5xx/正常/兜底全路径
- 配合运维 Nacos hl-order-service-v2-prod.yml contract.* 配置改公网 12301 域名(用户决策"直接用测试配置")
2026-04-28 10:29:54 +08:00

4.9 KiB

修复:12301 合同 API 异常分类细化, 网络/5xx 走兜底重试不再吞为业务失败

类型: 后端 BUG 修复 + 异常处理重构 关联: 工单 #1518 / PR #1520 / 用户(wx)正式订单 HL20260428095227-1084 实测反馈 日期: 2026-04-28 影响范围: 合同自动签约链路, 仅限熔断/超时/服务端错误场景, 正常业务无影响


现象

正式环境订单 HL20260428095227-1084 已支付定金后,清单确认触发自动签约失败:

  • 时间: 2026-04-28 10:02:59 (清单确认 +10s)
  • 通知: INAPP/SMS/MINIAPP 给用户 + WEWORK 给 admin 839
  • DB: contract 表 0 行(从未创建成功)

根因

两层 BUG:

  1. 配置层(运维侧): 正式 Nacos hl-order-service-v2-prod.ymlcontract.platform.standard.base-url=http://192.168.100.182:9301 是测试机房内网 IP, 正式 k3s 集群路由不到 → 每次 SocketTimeoutException(10s)
  2. 代码层(本 PR 修): TourageApiClient.doRequest 在 catch (Exception e) 把所有异常包成 BusinessException(TOURAGE_API_CALL_FAIL), ContractEventListener.onChecklistConfirmed 优先 catch BusinessException 走"立即创建紧急待办, 不重试", 真正的"5xx/超时走兜底重试"分支永远走不到

本 PR 修复 (代码层)

TourageApiClient.doRequest 的 catch 链拆细:

异常类型 旧行为 新行为 路径
ResourceAccessException (网络/超时) catch Exception → BusinessException → 不重试 RuntimeException → ContractEventListener catch (Exception) 兜底 走重试
HttpStatusCodeException 5xx 返 errorNode → ContractApplyResult.fail RuntimeException → 兜底 走重试
HttpStatusCodeException 4xx 返 errorNode → ContractApplyResult.fail + rawResponse 保留原行为(返 errorNode) 不重试,审计入库
其他 Exception BusinessException BusinessException 不变

4xx 行为为何保留

原始 dev agent 第一版实现是 4xx 抛 BusinessException, 但 TourageContractPlatform 的 5+ 个调用方依赖 if (apiClient.isSuccess(response)) ... else { result = ContractApplyResult.fail(getErrorMessage(response)); result.setRawResponse(response.toString()); } 模式, 要把错误 + rawResponse 入库审计。复审时改回保留 errorNode 返回行为, 确保 isSuccess(response)=false + getErrorMessage(response) 正常工作, 不破坏审计链路。

配置层修复 (运维做)

由用户决策 "直接用测试环境配置就行":

正式 Nacos prod namespace hl-order-service-v2-prod.ymlcontract: 段需要替换为测试环境版本 (https://open-api.mr.mct.gov.cn + 3 家旅行社凭证完整). 详细 yaml + Step 1-5 操作步骤见工单 #1518 评论 + test/cr-audit-data/round2/contract-prod-nacos-update.md:

  • standard.base-url / sync.base-url: http://192.168.100.182:9301https://open-api.mr.mct.gov.cn
  • agencies 块的 hulai/qianshou/hulai-wenlu 的 mch-id/app-id/sign-key/team-report-* 与测试环境完全一致
  • 3 处差异化: callback-base-url 改正式域名 / sign-url-proxy/qrcode-url-proxy 留空(测试用 192.168.100.236 代理正式没有)

单测覆盖 (TourageApiClientTest 新增 7 用例)

  • callApi_resourceAccessException_throwsRuntimeException 网络/超时 → RuntimeException
  • callApi_4xxStatus_returnsErrorNode 4xx → errorNode (审计保留)
  • callApi_5xxStatus_throwsRuntimeException 500 → RuntimeException 走重试
  • callApi_503Status_throwsRuntimeException 503 边界
  • callApi_401Status_returnsErrorNode 401 → errorNode
  • callApi_success_returnsJsonNode 正常 JsonNode
  • callApi_otherException_throwsBusinessException 兜底业务异常

部署后预期

修复后 + Nacos 配置纠正 + 服务重启 + 真订单端到端跑通后:

  • 正常签约: 12301 返回 contractNumber → contract 表新增 PENDING/SIGNED 记录 → 用户收到"请签合同"短信
  • 12301 间歇性 5xx: ContractEventListener 走重试分支 → 默认重试若干次, 仍失败才告警
  • 12301 网络异常: 同上走重试
  • 12301 4xx (鉴权/参数): 仍走"立即告警不重试"(由 isSuccess+getErrorMessage 模式判定)

前端 / 运营关注

零影响(全部是后端内部异常处理优化):

  • 用户视角接口行为完全等价
  • 只有"间歇性 12301 5xx 抖动"或"网络瞬断"时, 用户体验从"立刻看到 CONTRACT_FAILED 短信"变成"系统自动重试后再决定", 体验改善

后端部署

  • mvn compile -pl hl-order-service-v2 -am 通过 (2 次)
  • 仅需重启 hl-order-service-v2 (4 实例) 即生效
  • 必须配合运维改 Nacos contract.platform. 配置*(单独本代码 PR 不能修复合同失败, 配置才是根因)
  • 运营手动补建本订单 HL20260428095227-1084 合同 (Nacos 改完 + 服务重启后 → 调 admin API 或线下报备)

合并

  • PR #1520 squash merge 到 dev (sha 29d3b1d0)
  • 工单 #1518 待 Nacos 配置 + 数据补建完成后再关闭