老板拍桌子说3天搞定某个电商平台的订单接口,我拍胸脯说没问题。结果整个11天没发文,全在修bug。今天把11个坑扒干净,给对接API的兄弟当个避雷针。
先说第一个坑,签名算法。文档写“对参数按字典序排序后拼接密钥”,我拿Java的TreeMap排完,用MD5加密,本地跑通,一上线就报签名错误。查了3小时,发现对方服务端用的不是UTF-8,是GBK。我代码里没指定字符集,默认用了系统编码,生产环境是CentOS,locale设的zh_CN.GB18030。那行“MD5Util.encrypt(paramStr)”直接废了。改写成“paramStr.getBytes(“UTF-8”)”才过。坑在文档没写编码,自己得主动问对方技术。
第二个坑,时间戳格式。文档写“timestamp为Unix时间戳”,我传了10位秒级。对方返回“时间戳无效”。排查发现他们实际要求13位毫秒级,但文档没更新。我加了个“System.currentTimeMillis()”转毫秒,又加了个判断,如果对方返回特定错误码,自动切回秒级重试。后来发现他们内部两个系统,一个用秒,一个用毫秒,接口网关没统一。
第三个坑,重试机制。订单接口偶尔返回503,我写了简单重试,每次间隔1秒,重试3次。第4次调用时,对方返回“重复订单号”。原来第一次调用其实成功了,只是响应超时,我重试时传了同一订单号,对方幂等性校验没做严,生成了两条订单。后来改方案:重试前先查订单状态,如果已存在就不提交,直接拿结果。
第四坑,字段名大小写。JSON里有个字段叫“orderId”,我代码里用“order_id”映射,Gson反序列化默认严格匹配。漏了这个字段,订单号一直为空。后来加@SerializedName注解,挨个字段对文档,发现还有三个字段也是驼峰和下划线混用。直接写个脚本跑一遍文档字段名,全改成统一风格。
第五坑,分页参数。文档写“pageSize最大100”,我传了200,对方没报错,但只返回50条。测试环境没发现,上线后用户说订单对不上。问对方才知道,超过100自动截成50,但文档没写。后来每次请求前做参数校验,超过上限就分段拉。
第六坑,回调通知。对方说下单成功后HTTP POST回调,我写了个接收接口,用request.getInputStream()读body。结果对方callback时没带Content-Type,body是空。查日志发现他们回调请求里把参数拼在URL上,不是JSON body。改写成同时支持query和body两种方式,根据Content-Type判断。
第七坑,IP白名单。开发时我把测试服务器IP加到了对方白名单,上线时忘了加生产IP。接口调用直接返回403,排查了半小时才发现。后来写了个脚本,每次上线前自动检测当前服务器IP是否在白名单里,不在就发告警。
第八坑,并发幂等。下单接口并发量一上去,出现重复订单。对方说他们幂等用的是订单号+时间戳组合,但时间戳精确到秒,同一秒两个请求就可能重复。我改成用UUID做幂等键,每次请求生成唯一值,对方服务端也改成了UUID校验。但改完发现他们老系统还有历史数据,幂等逻辑不兼容,又加了个版本号字段做兼容。
第九坑,超时设置。默认HTTP连接超时30秒,对方接口偶尔响应慢,导致线程池打满。我调成10秒连接超时,30秒读取超时,但对方某个批量查询接口必须60秒以上。后来对不同接口配置不同超时时间,用Map维护。
第十坑,错误码不统一。对方接口返回code=0表示成功,code=-1表示失败。但某次返回code=200,我以为成功,直接处理数据,结果数据是错的。问对方才知道code=200是“部分成功”,但只返回了成功部分的数据。后来把所有非0码都当异常处理,部分成功也按失败处理,让用户手动确认。
第十一坑,接口版本管理。对方升级了接口,加了新字段,老字段废弃。我没看更新日志,继续用老字段,结果某天突然返回空值。后来每次请求都带版本号,如果对方返回版本不匹配的提示,自动切到新接口。同时写了定时任务,每周拉一次对方接口变更日志。
最后总结,API对接最坑的不是技术,是文档和实际不一致。我后来养成了习惯:先写个测试脚本,把文档里每个参数、每个返回值、每个错误码都跑一遍,和文档逐行核对。发现差异直接截图发给对方技术,确认后再写代码。这个步骤花2小时,能省后面2周。
老板的3天上线最后搞了3个月,但踩完这11个坑,后面接其他平台接口快多了。上次接微信支付,只用了2天,因为把之前的坑全列了个checklist,每对接一个平台先跑一遍。
📎 延伸阅读
看完这篇,如果你想:
- 直接拿工具 → 回复”13“,我把跨境获客工具包发给你
- 系统学习 → 点击菜单”AI训练营”,从0开始跑通AI变现