# 修复: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.yml` 中 `contract.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.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.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 配置 + 数据补建完成后再关闭