对接 ERP 踩过的 6 个坑:字段名会骗人,成功也会说谎
摘要:ERP 对接失败的原因,很少是「不会调接口」。多数是把文档当成了事实:字段名以为抄对了、请求体以为放进去了、返回成功以为成了。这篇把 6 类反复出现的坑按现场还原,每类给出识别方法和防御动作,并说明重试、限速、人工补偿这三道防线各自的边界。 关键词:ERP 对接踩坑、金蝶云星空接口、用友集成、SAP 集成、推送失败排查
一、最贵的一句话:文档上就是这么写的
一个真实的对接现场。接口调通了,测试环境跑了几十笔都正常。上线第一天,第一张单推送失败,报错是一个看不懂的字段校验错误。
排查三个小时,原因很小:文档里字段写的是 FBillNo,实际接口要的是 FBillNo 之外还有一层 FEntity,而我们的代码把整张单平铺着送过去了。
这类坑最伤人的地方在于它不可预判:测试环境能过,说明业务逻辑是对的;但测试用例覆盖不到「结构层级」和「字段语义」这两种错误,它们只在上线后真实单据上暴露。
把常见坑归纳一下,基本是六类。前五类都发生在「你以为你抄对了」,第六类发生在「你以为你成功了」。
二、命名类:大小写、会话标识、备注名
坑一:字段名大小写与文档不一致。 文档里写 FNumber,代码里写 Fnumber,看起来一样,实际是两个键。有些接口对大小写宽容,有些直接忽略这个字段——不报错,只是数据没进去。这比报错更难查,因为请求成功、响应成功,只有你回头核对单据时才发现某个字段是空的。
识别方法:不要凭肉眼比对,把请求体字段清单和单据回读字段清单做一次机器比对。防御动作:请求体字段名集中在一个映射表里,不在业务代码里散写。
坑三:会话标识的大小写。 这类接口通常要先拿会话或用票据,票据字段名在不同版本里大小写不同。表现是「偶尔鉴权失败」,因为在某些调用路径下用的是缓存票据,缓存里那份是对的,新建的那份是错的。排查时容易怀疑到网络或并发,其实只是键名拼错了。
坑五:备注字段名与文档不符。 备注、摘要这类字段最容易被写错,因为它们在文档里通常有多个近义名(说明、备注、摘要、附言),而实际接口只认其中一个。表现是备注全部为空,但单据主体正常——于是没人发现,直到业务说「这张单看不出是哪批货」。
这三类的共同点是:它们不会让请求失败,只会让数据悄悄缺失。所以真正的防御不是小心,是回读校验——推完必须读回来比一次,不相等的字段要报出来。
三、结构类:请求体必须嵌套一层
坑二:请求体必须嵌套一层。
这是最典型的一种。文档给的示例是「表头字段 + 表体数组」,但示例的 JSON 是缩进展示的,很多人照着写成了平铺结构。接口收到之后不会报「结构不对」,而是把表头字段当成未知字段忽略,只处理了表体。
结果:单据生成了,但单据上的关键信息(日期、往来单位、单据类型)全是空的或者默认值。这种单据在系统里是「有效」的,能审核、能记账,只是内容不对。等到财务发现金额不对,已经过去几天。
防御动作:把请求体结构写成模板(表头一层、表体一层、字段映射一层),用模板渲染而不是手工拼 JSON。模板还有个好处:换平台只换模板,不动代码。
四、语义类:那个字段其实是另一张单的
坑四:供应商字段其实是应付单的。
这个坑的杀伤力最大,因为它看起来完全正常。你在做应收方向,看到接口里有个「供应商」字段,想当然认为它可以填客户,或者认为它用于备注来源。实际上这个字段属于应付方向的单据结构,在应收单据里传它,要么被拒绝,要么被当成另一个维度存进去,造成对账时金额挂在错误的往来单位上。
这类坑的根源是把「字段存在」当成「字段属于我」。一个接口往往同时服务多个单据类型,字段表是并集,不是交集。
识别方法:拿真实的、已审核的单据做回读,看每个字段的取值来源。防御动作:字段表按单据类型分别维护,不要共用一张全量表。
五、语义类之二:成功也会说谎
坑六:成功响应不等于业务成功。
很多 ERP 接口在业务校验失败时,HTTP 状态仍然是 200,只在响应体里返回一个业务状态码或错误列表。如果你的代码只判断 HTTP 状态,就会把失败当成功,继续推进后续流程——推送日志里一片绿色,实际单据一张没生成。
这个坑最阴的地方是延迟暴露:当天看不出问题,月底对账发现少了几十张单,回头查日志全是成功。
正确做法是双判定:HTTP 层判定通信成功,业务层判定单据是否真的生成、状态是否真的正确。两者都过才算成功。业务层判定的最可靠方式是回读:按单据编号或业务订单号反查,确认存在且关键字段一致。
这一条也是我们做推送设计时最先定下的规矩:一次推送的结果不是「请求返回什么」,而是「单据在对方系统里处于什么状态」。轻易云的转换与推送链路里,成功与否以回读状态为准,HTTP 状态只用来决定要不要重试。
六、三道防线:重试、限速、补偿
坑认全了,还得有防线,否则每次都要人守着。
第一道:自动重试。 只对「可重试错误」重试——网络超时、对方限流、临时不可用。参数错误、字段校验失败这类重试一万次也不会成功,必须直接判失败并报警。重试用指数退避,次数不宜多,三到五次足够;间隔从秒级起,避免连续冲击对方。
第二道:限速。 批量推送时最容易出事。对方接口能承受的并发和频率通常远低于你的处理速度,不限速的结果是被限流、被临时封禁,甚至影响当天其他业务的推送。做法是给推送队列设一个固定速率,宁可慢一点,也要稳。速率起步按每分钟几十次,再根据对方文档和实际响应调整。
第三道:人工补偿。 有些失败是自动处理不了的:单据已存在、期间已关闭、对方数据被人工改过。这类必须落到一个人工队列里,有明确的责任人和处理时限,不能只在日志里留一行红字。
三道防线的边界要写清楚:哪些错误自动重试、哪些直接失败、哪些进人工队列。模糊的边界会导致两个后果——该重试的没重试,或者该人工的反复重试把对方的额度耗光。
七、日志该留什么
推送日志不是给开发看的调试输出,是给财务和审计看的证据。所以要留四样东西:
一是请求的时间、单据标识、目标系统,让任何一笔都能被定位;二是请求体的关键字段快照(不是全量,全量太大且可能含敏感信息);三是响应体原文和业务状态码,区分「通信失败」和「业务失败」;四是重试次数与最终结果。
有这四样,月底谁问「这张单为什么没推到」都能在两分钟内回答。只留一行「推送失败」,等于没留。
这也是我们把集成转换做成独立一层的原因:转换规则、推送、重试、失败处置各自有位置,出问题能定位到层,而不是在一段几百行的脚本里找。轻易云的做法是把「结构映射」和「业务判定」拆开,映射错了改模板,判定错了改规则,互不牵连。
八、上线前的一张自检表
六个坑讲完,落到能执行的东西上。下面这张表建议在上线前逐项过一遍,每项都要有「谁确认、证据在哪」,不要只在会上说一遍。
| 检查项 | 判定标准 | 谁确认 |
|---|---|---|
| 字段名一致性 | 请求体字段清单与单据回读字段清单机器比对,差异为零 | 集成开发 |
| 请求体层级 | 表头 / 表体 / 映射三层结构与模板一致,不用手工拼 JSON | 集成开发 |
| 会话票据键名 | 新建与缓存两条路径都能鉴权成功 | 集成开发 |
| 字段归属 | 每个字段标注所属单据类型,跨方向字段不共用 | 实施顾问 |
| 备注类字段 | 推送后回读,备注不为空 | 实施顾问 |
| 成功判定 | 业务层回读通过才算成功,HTTP 200 不算 | 集成开发 |
| 重试白名单 | 可重试错误有明确清单,清单外一律不重试 | 集成开发 |
| 限速配置 | 推送队列有固定速率,压力测试下不触发对方限流 | 集成开发 |
| 人工队列 | 有责任人、有处理时限、有每日清理机制 | 财务经理 |
| 日志四要素 | 时间、单据标识、请求快照、响应原文齐全 | 集成开发 |
这张表的价值在于把「经验」变成「检查」:六个坑里任何一个没人认领,都会在上线后以故障的形式重新出现。
顺带说一句顺序:先做回读,再做重试。很多团队反过来,先把重试写得花团锦簇,结果回读没做,失败了也发现不了,重试只是在重复错误。回读是地基,重试是加固。这张表也不该只在上线前用一次——每次换接口版本、换平台、换对接人,都值得重新过一遍,因为坑的形状会变,底层的判断标准不变。
九、给顾问的四条动作
第一,把字段表按单据类型分开维护,别再用一张全量表去套所有方向。供应商字段的坑,本质就是这张表没分开。
第二,推送成功一律以回读为准。HTTP 200 只说明对方收到了,不说明对方办成了。
第三,重试范围先写清楚再写代码:可重试错误用白名单,不在白名单里的一律不重试。
第四,留一个有人负责的人工补偿队列。凡是「自动处理不了」的失败,都应该有人知道、有人管、有时限。