- 网络/5xx 走兜底重试(ResourceAccessException + HttpStatusCode 5xx → RuntimeException) - 4xx 保留原 errorNode 返回行为(不破坏 isSuccess+getErrorMessage 调用方 + 保留审计 rawResponse) - 单测新增 7 用例覆盖网络/4xx/5xx/正常/兜底全路径 - 配合运维 Nacos hl-order-service-v2-prod.yml contract.* 配置改公网 12301 域名(用户决策"直接用测试配置")
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:
- 配置层(运维侧): 正式 Nacos
hl-order-service-v2-prod.yml中contract.platform.standard.base-url=http://192.168.100.182:9301是测试机房内网 IP, 正式 k3s 集群路由不到 → 每次 SocketTimeoutException(10s) - 代码层(本 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.yml 的 contract: 段需要替换为测试环境版本 (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:9301→https://open-api.mr.mct.gov.cnagencies块的 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网络/超时 → RuntimeExceptioncallApi_4xxStatus_returnsErrorNode4xx → errorNode (审计保留)callApi_5xxStatus_throwsRuntimeException500 → RuntimeException 走重试callApi_503Status_throwsRuntimeException503 边界callApi_401Status_returnsErrorNode401 → errorNodecallApi_success_returnsJsonNode正常 JsonNodecallApi_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 配置 + 数据补建完成后再关闭