同步对接里真正要留心的事
一句话总结
同步 REST 集成的难点不在调用,而在等待——如果不设置超时,对方系统的故障就会原样变成我们系统的故障。
为什么同步集成真正的风险是“等待”
调用对方的 REST 系统很容易,困难出现在对方响应缓慢时。
假设我们的页面同步调用对方 API,而对方延迟 30 秒。
- 我们的 WAS 线程会被占用 30 秒
- 用户在页面前等待,通常会按刷新
- 刷新会再产生一个请求,前一个请求却仍然存活
- 线程迅速耗尽,对方系统的故障变成我们系统的故障
因此,同步集成必须设置超时,而且有两类。
연결 타임아웃(connect) : 상대와 TCP 연결이 맺어질 때까지 → 짧게 (1~3초)
응답 타임아웃(read) : 응답을 다 받을 때까지 → 업무에 따라 (5~30초)
连接超时必须设置得短。 如果对方服务器已经宕机,连接应立即失败。若设为 30 秒,对方宕机期间,我们的每个线程都会被占用 30 秒。
而且只有超时仍然不够。对方持续变慢时,我们也会持续被拖住,此时需要熔断器。当失败率超过阈值后,在一段时间内不再调用并立即失败。有些场景中,“快速失败”比“等待缓慢成功”更好。
超时不等于“对方没有收到”
这是最重要的一点。
发生超时时,我们无法区分对方是没有收到请求, 还是已经处理,只是响应没有回来。
发送订单时发生超时,是否应该重发?
- 如果对方没有收到,就应重发
- 如果对方已经处理,重发就会造成重复订单
这个问题不能靠重试解决,而要靠幂等性解决。发送方为每次请求附上唯一键(报文编号、Idempotency-Key),接收方再次收到相同键时不重复处理,而是原样返回首次响应。这样重发才是安全的。后续模块会通过实验讲解。
发送前验证——在离开我方前拦截
发给对方之前,我们必须先验证以下内容。
- 必填值:定义书中的必填项是否齐全
- 长度:按字节计算是否超长
- 类型/格式:日期格式是否正确,数字字段中是否混入字符
- 代码值:是否属于定义书规定的代码集合
如果不做验证,就只能从对方系统的错误响应中得知问题。这样会:
- 浪费一次往返时间
- 让我们的错误堆满对方系统日志,消耗双方集成人员的精力
- 批量处理时一次爆发数千条错误
**“坏数据在我方拦住”**是集成开发的基本礼仪。
单独保留集成日志
集成日志混在应用日志中,事后很难查找。应建立专用日志,每次调用记录一行,至少包含以下字段。
2026-08-19T14:03:22.145+0900|IF-ORD-001|ORDER-SYS|PARTNER-API|0000|182|a1b2c3d4
시각 인터페이스ID 송신 수신 응답코드 소요ms 추적ID
- **跟踪 ID(trace_id)**尤其重要。与对方系统日志核对时,靠它就能定位。应随请求头发送,并在定义书中要求对方也记录。
- 记录耗时后,面对“最近变慢了”的说法就能给出证据。
- 记录响应代码后,可以统计错误分布。
同时,不要在日志中保存个人信息。 身份证号、账户号、卡号应脱敏或完全不记录。集成日志通常长期保存,风险更高。
大批量处理不要使用同步方式
“向对方发送十万条订单”这类需求不应使用同步 REST。即使每条只需 100ms,十万条也约需 2.8 小时;期间只要中断一次,就不知道处理到了哪里。
有三种替代方案。
- 文件批处理——打包发送,再以文件接收结果
- 队列——异步发送,通过独立渠道通知结果
- 批量 API——一个请求包含 N 条(通常为 100~1000 条),返回逐条结果
选择第 3 种方式时,必须定义:如何处理部分失败。 100 条中有 3 条失败时,是整体回滚,还是处理 97 条并只返回 3 条失败?定义书没有说明,双方就会采用不同实现,而这种差异通常几天后才以“记录数对不上”的形式暴露。
在实际项目中
这种故障总以相同方式发生:对方 API 变慢,我们的页面卡住,用户按下刷新,又产生一个请求。前一个请求仍然存活,于是线程占用翻倍。几分钟后 WAS 线程耗尽,连与对方完全无关的页面也全部停止。
此时监控中,我们系统的 CPU 和内存看起来都正常,因为线程不是在工作,只是在等待。结果大家会先从我方查原因,白白浪费时间。
这正是必须单独保留集成日志的原因。日志混在应用日志中,要判断“对方从什么时候开始变慢”会花很久;若按固定格式逐行记录接口 ID、响应代码与耗时,一分钟就能得到答案。