API对接实战:从协议分层到生产级错误排查的完整方法论
跟API对接死磕了三年,这句话听起来像一句吐槽,实际上是在说一个常态:外部接口不像自己项目里的代码,你看不见实现,改不了逻辑,只能靠文档、请求、响应和日志去反推对方的意图。三年里我接过支付、ERP、大模型、设备SDK、推送通道、企业微信机器人、行情接口,几乎每天都是在“参数怎么不对”“签名怎么又失败”“为什么生产环境才报错”这些声音里度过的。到后来我意识到,API对接的核心能力不是记住某个平台的接口写法,而是建立一套从需求确认到上线维护都稳定的方法。这篇博客就把这套方法、常见坑和排查思路完整整理出来,适合刚接触第三方接口的开发者,也适合已经对接过不少系统、却总在排错上浪费时间的团队。
1. 先搞清楚API对接到底在接什么
1.1 API对接的三种协议层:传输、鉴权、业务
很多人第一次对接API时,以为只要照着文档把请求发出去就行了。实际上,一次完整的API对接通常由三层组成。
传输层决定请求能不能到达服务端。协议是HTTP还是HTTPS,域名是否通,端口是否开放,证书是否有效,这些都属于传输层。本地经常出现的failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen就是典型的传输层问题,Docker Desktop没有启动,或者Windows下管道路径不对,HTTP请求根本发不出去。这类问题看状态码没有意义,因为状态码根本不存在。
鉴权层决定服务端认不认你这个调用方。API Key、Token、OAuth、签名、IP白名单、证书双向认证,都在这层。最常见的现象是请求发出去了,也得到了HTTP 403,但业务功能没有任何参数错误。比如transport failure for /api/agentpreset.list: http 403,这类错误要先查API Key有没有对应接口权限,再查IP是否在白名单里,最后才查业务参数。
业务层才真正处理你的数据。请求体里的字段名、字段类型、枚举值、长度限制、响应结构、回调参数,都在这层。三层必须分开排查,否则很容易出现“改了十次参数仍然报错,最后发现是API Key没有权限”的情况。
三年经验里,最容易浪费时间的不是业务层,而是传输层和鉴权层。因为业务层的问题错误信息通常很清楚,鉴权层的问题却经常被框架和网关注销掉细节。
1.2 对接前必须确认的“契约五要素”
不管对接什么系统,动手写代码之前,先确认五件事:
| 要素 | 需要确认的内容 | 落地方式 |
|---|---|---|
| 接口地址 | 测试环境、沙箱环境、生产环境的域名和路径是否不同 | 写入不同环境的配置文件 |
| 请求方法 | GET、POST、PUT、DELETE,是否支持批量接口 | 按文档实现,不要自己猜 |
| 请求头 | Content-Type、Accept、Authorization、自定义Header | 固定Header封装在Client里 |
| 请求体 | 字段名、字段类型、是否必填、默认值、长度限制 | 用结构体或DTO定义,不要Map到处传 |
| 响应结构 | JSON还是XML,字段命名风格,错误码和message格式 | 先保存样本,再写解析代码 |
除了这五要素,还要单独确认两件事:错误码表和限流规则。
错误码表决定你的异常处理怎么写。有的平台用HTTP状态码区分大类,再用业务错误码区分细节;有的平台所有失败都返回HTTP 200,只在body里写code=40001。如果没有拿到错误码表,你的代码只能对状态码做分支,无法对业务错误做精细处理。
限流规则决定你的调度策略。每秒几次,每分钟几次,突发是否允许,超限后是返回429还是直接断开连接,都需要在对接前确认。否则上线第一天就可能因为循环调用把API Key封掉。
1.3 按阶段拆解对接过程,别让联调变成黑盒
我见过最糟糕的对接方式是这样:拿到文档就开始写完整业务模块,写了三天,然后拿去联调,失败,接着开始从头看日志。看上去很努力,实际上没有任何阶段性验证,一旦出错,完全不知道是哪一层的问题。
正确的做法是把对接过程拆成四个阶段,每个阶段都有明确的退出标准:
- 环境验证:确认网络通、HTTPS证书有效、测试账号能登录。退出标准是本地能访问服务端任意一个公开接口。
- 最小请求验证:用curl或脚本发起一次最简单的请求,不写业务逻辑,只测鉴权。退出标准是拿到HTTP 200和最小响应体。
- 业务字段验证:把真实业务的参数逐步加进去,一次只加一个字段。退出标准是所有必填字段都通过服务端校验。
- 异常分支验证:故意传错参数、传过期Token、触发限流,确认服务端错误码和自己的异常处理逻辑能对上。
这四个阶段不是一个一个排着做,而是每做一个阶段,就保存对应的请求响应样本。这样后面代码写错了,能立刻知道是业务代码问题,还是从第一步就错了。
2. 一个可复用的最小对接流程
2.1 先写最小请求,目标只是拿到一次成功响应
不要一上来就用框架封装。最稳的做法是先抛开业务代码,用curl发一个最小请求。
curl -X POST "https://api.example.com/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-xxxx" \ -d '{"model":"example-model","messages":[{"role":"user","content":"hello"}]}'这一步只看三件事:能不能连上、鉴权是否通过、服务端有没有返回JSON。如果curl都失败,就不要继续写代码。这时需要检查域名解析、防火墙、代理、证书,而不是检查SDK配置。
如果原始文档没有明确模型名,或者模型列表会变化,建议先到服务商控制台确认当前可用的模型名,不要凭记忆写。实际对接中经常出现The supported API model names are ...之类的错误,就是模型名拼错或者用了旧版本的名称。
2.2 用代码发起请求,但要保证你能看到原始报文
curl跑通之后,再用代码实现。使用Python举例,写一个最原始的请求函数,重点是把响应完整打印出来,不要用框架解析后只留下对象。
import requests API_URL = "https://api.example.com/v1/chat/completions" API_KEY = "sk-xxxx" def call_minimal(): resp = requests.post( API_URL, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}", }, json={ "model": "example-model", "messages": [{"role": "user", "content": "hello"}], }, timeout=(5, 30), # 连接超时5秒,读取超时30秒 ) print("HTTP Status:", resp.status_code) print("Response Headers:", resp.headers) print("Response Body:", resp.text) return resp这段代码的作用不是给生产用,而是让你看到真实报文。很多对接问题出在框架隐藏了细节,比如Spring Boot的RestTemplate默认可能对某些HTTP状态码抛异常,你看不到body里的业务错误码。先打印原始文本,确认服务端到底返回了什么,再决定怎么解析。
这里要注意,API_KEY在示例里直接写在代码中只是为了演示。实际项目中需要通过环境变量或配置中心注入,不能提交到仓库。
2.3 响应解析:先保存样本,再写映射
拿到成功响应后,把响应体保存为sample.json,再写解析逻辑。
{ "id": "chatcmpl-123", "object": "chat.completion", "created": 1700000000, "model": "example-model", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello!" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 8, "completion_tokens": 4, "total_tokens": 12 } }然后使用Pydantic定义模型:
from pydantic import BaseModel class Message(BaseModel): role: str content: str class Choice(BaseModel): index: int message: Message finish_reason: str class ChatCompletion(BaseModel): id: str object: str created: int model: str choices: list[Choice]这样写的好处是字段类型不匹配时,Pydantic会给出清晰错误。比如服务端把created返回成字符串,你会立刻看到“输入不是整数”,而不是在业务代码里用错类型。
容易踩的坑是服务端存在可选字段。有的接口在某种条件下不会返回usage,或者choices为空数组。解析模型要区分“必填字段”和“可选字段”,不要因为一次响应没有某个字段,就把整个结构体判为失败。
2.4 用Mock和契约测试隔离第三方依赖
第三方API不适合在单元测试里真实调用。一方面慢,另一方面不稳定,还会消耗配额。可以用Mock工具模拟响应。
import responses import requests @responses.activate def test_call_api(): responses.add( responses.POST, "https://api.example.com/v1/chat/completions", json={"id": "mock", "choices": []}, status=200, ) resp = requests.post( "https://api.example.com/v1/chat/completions", json={"model": "example-model"}, timeout=10, ) assert resp.status_code == 200Mock不能替代真实联调,但能让单元测试稳定。生产级别的对接,还要引入契约测试,把请求和响应样本保存下来,每次升级依赖或修改解析逻辑时重新比对,防止第三方接口字段变化后,你这边没有感知。
3. 三年里最常见的API错误和排查路径
3.1 按状态码定位,按错误码定因
HTTP状态码只能说明大类,不能直接定位根因:
- 400 通常是客户端请求有问题,但到底是什么问题,要看body里的message。
- 401 认证失败,可能是Token失效、格式错误、过期。
- 403 权限不足,可能是Key没有对应权限、IP白名单没加、账号被禁用。
- 429 限流或并发超限,需要做退避。
- 5xx 是服务端问题,但也要区分是网关错误还是后端业务错误。
- 499/Connection lost 这类错误,往往是客户端超时或连接被切断,状态码可能根本没有返回。
一个常见的误区是:只要看到400就认为是“参数错误”,然后把所有字段逐个试一遍。实际上,400经常是JSON格式不对、Content-Type错误、字符串被转义、模型名不存在,甚至某个Header缺失。正确做法是先看响应体里的code和message,再看HTTP状态码。
3.2 常见API错误分类表
把三年里最常见的错误整理成一张表,排查时按表走:
| 错误现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
400: The thinking_budget parameter must be a positive integer | 参数类型错误,传入了0、负数、字符串或小数 | 对照文档检查字段类型和取值范围 | 传正整数,或去掉该字段使用默认值 |
400: This model's maximum context length is 1048576 tokens... | 输入上下文超过模型限制 | 统计prompt和历史消息的token数 | 截断历史、分块请求或换更大上下文模型 |
connection lost mid-response. the response above may be incomplete | 流式响应中途断开 | 检查网络代理、读取超时、服务端负载 | 增大读取超时,使用SSE断线重连,记录已接收内容 |
529 overloaded. this is a server-side issue, usually temporary | 服务端过载 | 查看服务商状态页 | 指数退避重试,避免集中重试造成雪崩 |
transport failure for /api/agentpreset.list: http 403 | 鉴权或权限不足 | 检查API Key权限、IP白名单、账号状态 | 申请对应接口权限,或在控制台添加白名单 |
login failed. check api token or gitlab version | Token失效或版本不匹配 | 重新生成Token,确认GitLab API版本 | 更新到兼容版本,Token不要手动过期 |
failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen | Docker服务未启动/管道不存在 | 启动Docker Desktop,检查DOCKER_HOST | 重启Docker Desktop,修复本地环境变量 |
这张表并不是让你死记错误文案,而是要理解每一类错误的共性。参数错误看类型和范围,鉴权错误看权限和Token,连接类错误看网络和超时,过载类错误看重试策略。
3.3 从一条错误信息倒推排查步骤
以connection lost mid-response为例,完整的排查顺序应该是:
- 先确认请求是否发出:查看客户端日志,有没有请求起始记录。
- 确认服务端是否响应:用curl复现,看能否稳定复现,还是偶发。
- 抓包或抓取原始报文:确认响应在哪个位置中断,是完全没有body,还是收到一半后断掉。
- 检查客户端超时设置:读取超时设置太短,会导致连接被本地主动断开。
- 检查网络代理和负载均衡:代理服务器空闲超时、Nginx proxy_read_timeout 太小,都会造成“响应被截断”。
- 检查服务端状态:如果是流式接口,服务端负载过高也可能导致流中断。
- 最后才考虑代码解析问题:SSE解析遇到半包、断包,也会表现为“响应不完整”。
这个顺序的核心思想是:从最靠近“事实”的地方开始排查,而不是从最熟悉的地方开始排查。很多人在第4步就怀疑是框架的Bug,结果花了半天时间,最后发现是本地代理连接被重置。
4. 鉴权与安全:API Key、Token、签名怎么放才安全
4.1 API Key不能出现在代码和前端
GitHub上天天有人扫描代码仓库里的API Key。把Key写在JAVA类常量里,或者写在前端环境变量里再被打包进JS,都是高危行为。前端拿到的API Key,等于公开给所有人,别人可以冒充你的应用调用接口,产生费用或污染数据。
正确的做法是API Key只存在于后端。通过环境变量或配置中心注入,不在代码库中保留明文。
# .env 示例,不要提交到Git API_KEY=sk-xxxxxxxx API_BASE_URL=https://api.example.comimport os API_KEY = os.getenv("API_KEY") if not API_KEY: raise RuntimeError("API_KEY is not set")生产环境还应该做到最小权限和定期轮换。不同的功能模块使用不同的Key,如果某一个Key泄露,只需要吊销该Key,不影响其他服务。
4.2 签名机制、时间戳和防重放
很多开放平台不用简单API Key,而是要求每个请求做签名。签名通常是把请求参数排序、拼接、加上时间戳和随机数,再用AppSecret做HMAC-SHA256。
import hashlib import hmac import time import random import string def generate_sign(params: dict, secret: str) -> str: # 1. 过滤空值和sign本身 filtered = {k: v for k, v in params.items() if v != "" and k != "sign"} # 2. 按键名升序排列 sorted_keys = sorted(filtered.keys()) # 3. 拼接成 query string raw = "&".join(f"{k}={filtered[k]}" for k in sorted_keys) # 4. HMAC-SHA256 signature = hmac.new(secret.encode(), raw.encode(), hashlib.sha256).hexdigest() return signature签名机制存在的意义有两个:认证和防篡改。如果请求体被改了一个字段,签名就对不上,服务端可以拒绝。时间戳和nonce字段则用来防重放,同一签名只能在一定时间内有效。
这里容易踩的坑有三个:
- 排序时忽略了参数名的大小写规则,导致签名结果不一致。
- 拼接字符串时没有对URL编码做统一,导致中文或特殊字符出现偏差。
- 把签名用的原始字符串打到了日志里,等于泄露了签名逻辑。
解决方式是先把签名生成逻辑封装成独立函数,用和文档要求完全一致的方式做单元测试,测试用例里包含中文、空值、大小写混排参数,确保每个平台都能通过。
4.3 已有Token体系与外部API Key如何共存
很多Java Spring Boot项目已经有自己的登录Token体系,内部用户登录后拿一个JWT,再调用外部API时,如果直接把API Key写在业务代码里,所有内部用户都能通过这个服务调用外部API,风险很大。
更合理的结构是做一个“凭证管理层”。内部请求先经过自己的认证拦截器,解析用户Token后,由后端服务从密钥管理服务获取外部API Key,再用这个Key发起第三方请求。Key不进入前端,也不进入普通业务线程。
@Configuration public class ExternalApiClientConfig { @Value("${external.api.key}") private String apiKey; @Bean public RestTemplate externalApiRestTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add((request, body, execution) -> { request.getHeaders().setBearerAuth(apiKey); return execution.execute(request, body); }); return restTemplate; } }这里的关键是:内部Token只负责“你是谁”,外部API Key只负责“哪个服务在调用”。两者不要混用。如果外部系统支持临时凭证或STS,那更好,可以进一步缩小Key的暴露范围。
5. 不同对接场景的技术差异
5.1 支付接口:对账、证书和回调验签
支付类接口是所有API对接里最需要谨慎的一类,因为涉及资金。微信支付、招行薪福通这类系统,通常要求商户号、API密钥、证书,并且强调回调验签。
最容易踩的坑有三个:
- 回调接口只验签不校验金额。攻击者模拟一个签名正确的回调,把金额改小,业务系统就以为支付成功。正确做法是验签通过后,用商户订单号查询平台订单,对比金额、状态和商户号。
- 重复回调没有做幂等。支付平台为了保证通知成功,会重试多次。业务系统必须用订单号加状态机保证只能流转一次。
- 金额单位不一致。很多支付接口用分,而业务系统用元,差100倍,一上线就是事故。
支付接口的联调不能只在沙箱环境做一次成功流程,要主动测试失败回调、重复回调、金额不匹配回调。
5.2 大模型API:上下文长度、模型名、连接中断和限流
大模型API在最近两年对接得最多。OpenAI、DeepSeek、讯飞星火、Gemini、智谱,很多都提供OpenAI兼容格式,看起来差不多,实际差异却不小。
常见的问题是:
- 模型名写错。不同平台的模型名完全不同,即使兼容OpenAI格式,也需要到控制台确认当前可用的模型名。报错信息里出现的
The supported API model names are ...,就是模型名不匹配。 - 上下文超长。输入文本、历史消息、系统提示词加在一起,超过了模型的上下文窗口,比如
maximum context length is 1048576 tokens。这需要做Token统计和截断策略。 - 流式连接中断。SSE流式响应可能因为网络代理、读取超时、服务端负载而断开。客户端要做好半包解析和断线重连。
- 529过载。服务端临时过载,需要退避重试,而不是立刻同一秒再打一次。
Python流式调用示例:
import requests def stream_chat(): resp = requests.post( API_URL, headers={"Authorization": f"Bearer {API_KEY}"}, json={ "model": MODEL_NAME, "messages": [{"role": "user", "content": "讲个故事"}], "stream": True, }, stream=True, timeout=(5, 300), ) for line in resp.iter_lines(): if not line: continue text = line.decode("utf-8") if text.startswith("data: "): payload = text[6:] if payload == "[DONE]": break # 解析JSON并处理增量内容生产环境不能忽略stream=True时的超时设置,读取超时要比一次完整生成的时间更长,否则长文本生成时连接会被本地主动断开,正好出现connection lost mid-response。
5.3 企业内部系统与设备SDK:局域网、版本和协议差异
企业内部系统对接,比如U8、飞利浦MX550、海康云眸、企业微信、极光推送,和对接公网开放平台还不一样。
U8这类ERP系统,很多对接不是走REST API,而是走中间数据库表、COM组件或WebService。对接前要先确认是实时接口还是中间表同步。如果是中间表,还要确认事务控制、主键策略和批处理窗口。
海康云眸、企业微信这类平台,对外提供的是标准HTTP API,但权限模型比较复杂。比如云眸的AccessToken、企业微信的corpsecret和suite_token,都需要缓存并定时刷新,不能每个请求都获取。
设备SDK和本地服务对接,比如EasyMRCP对接FreeSWITCH、Plant Simulation与PLC对接,除了API本身的协议,还要关注底层通信链路和版本兼容。login failed. check api token or gitlab version这类错误,表面上是Token问题,实际上经常是客户端版本太旧,服务端已经不支持旧协议。
对接这类系统,一定要先确认接口类型:是HTTP API、SDK封装、数据库中间表,还是消息队列。不同方式的排错路径完全不同。
5.4 开源库对接:不要跳过版本和依赖关系
CCXT对接Binance/OKX、Ruoyi-AI对接本地大模型,这类用开源库的场景,最大的风险是版本错位。
开源库通常封装得很方便,但它本质上是“别人写的API对接代码”,同样会踩到参数变化、接口弃用、服务端协议更新等问题。我见过一个项目,用了半年CCXT突然无法下单,查了很久才发现是交易所API更新了签名算法,本地的CCXT版本还是旧版,不兼容。
使用开源库时,至少做到:
- 锁定版本,不要每次构建都拉最新master。
- 升级前看ReleaseNote,确认是否涉及接口签名、请求参数、响应结构的变化。
- 保留一个最小复现样例,升级库后第一时间跑通样例。
- 不要把开源库当成永不出Bug的黑盒,它的日志和调试模式往往比自己的业务代码更重要。
6. 生产环境不是能跑通就行
6.1 超时、重试、幂等和连接池
学习环境里,接口调用一次成功就够了,但生产环境里,外部API随时可能变慢、超时、返回5xx。所以第一件事就是给所有外部调用设置明确的超时。
以Java RestTemplate为例:
@Bean public RestTemplate externalApiRestTemplate(RestTemplateBuilder builder) { return builder .setConnectTimeout(Duration.ofSeconds(5)) .setReadTimeout(Duration.ofSeconds(30)) .build(); }连接超时不能太长,一般3到5秒;读取超时要按接口特性区分,普通查询10秒,大模型流式生成可能要几分钟,不能统一设置。
重试要区分读操作和写操作。读操作可以重试,写操作必须谨慎。如果是支付回调、订单创建这类写操作,必须使用幂等键,否则重试会造成重复下单、重复扣款。
重试策略推荐指数退避加抖动:
import random import time def retry_with_backoff(attempt): base = 2 ** attempt jitter = random.uniform(0, 0.5) time.sleep(base + jitter)连接池也要限制。如果每个请求都新建TCP连接,到高并发时,本地端口和文件描述符会被耗尽,反而比外部服务先挂掉。生产环境要对第三方API的线程池做隔离,不能和业务线程池共用。
6.2 第三方API的隔离、熔断和降级
外部API一旦故障,会带来连锁反应。比如一个促销活动请求商品库存,库存系统依赖第三方ERP,ERP变慢后,整个促销接口也被拖垮。
解决思路是隔离和熔断。给不同第三方API分配独立的线程池,配合Resilience4j或Sentinel做熔断。当失败率达到阈值时,直接短路,不再请求第三方,而是快速返回降级结果。
@CircuitBreaker(name = "externalERP", fallbackMethod = "mockStock") public Stock queryStock(String skuId) { return erpClient.queryStock(skuId); } public Stock mockStock(String skuId, Throwable t) { return new Stock(skuId, -1, "unknown"); }降级结果不能让业务无感知,至少要记录日志和指标。库存返回unknown后,前端要提示“库存服务暂时不可用”,而不是把unknown当成0去下单。
6.3 日志、监控和告警怎么配合
对接外部API时,日志必须能串起整条链路。建议每个外部请求统一记录:
- 请求ID(自己系统生成)
- 外部链路ID(如果服务端返回了 request_id、trace_id)
- 接口名称和URL
- HTTP状态码和业务错误码
- 耗时
- 关键响应字段(成功时记录摘要,失败时记录完整错误信息)
不能记录完整请求体和响应体,尤其是支付、登录、API Key相关的数据。建议做字段脱敏,比如API Key只记录后四位。
监控指标至少要有:
- 请求总量和成功率
- 错误码分布
- P50、P95、P99耗时
- 流式接口的中断率
告警规则要避免“一报错就报警”。可以按失败率阈值、限流次数、连接中断率做分级告警。比如成功率降到95%以下通知,降到90%以下电话告警,避免外部API抖动导致告警疲劳。
7. 三年后沉淀下来的API对接清单
7.1 对接前检查清单
动手开发之前,把这条清单过一遍:
- 测试环境地址和生产环境地址是否分别确认。
- API Key、AppSecret、证书是否拿到,是否有最小权限。
- 接口文档版本是哪一版,是否覆盖要对接的所有接口。
- 沙箱环境是否有真实测试数据,还是需要自己构造。
- 是否拿到错误码表,而不是只靠HTTP状态码判断。
- 限流规则是什么,超过限制会返回什么。
- 回调或Webhook地址是否需要公网可达,是否要在内网打通。
- 是否存在字段类型、金额单位、时间格式等容易踩的隐藏规则。
7.2 联调中检查清单
- 先用curl或Postman拿到一次成功响应。
- 确认原始报文,不只看框架解析后的对象。
- 确认鉴权方式:API Key放Header还是Body,Token多久过期。
- 确认响应结构:字段是否可能缺失,类型会不会变化。
- 逐个添加业务字段,每加一个就验证一次。
- 测试失败场景:参数错误、Token过期、限流、服务端5xx。
- 测试幂等场景:重复提交同一请求,业务结果是否一致。
- 测试回调场景:重复回调、乱序回调、金额不一致回调。
7.3 上线前检查清单
- 密钥是否已经写入配置中心或环境变量,代码库中没有明文。
- 连接超时和读取超时是否分别配置。
- 写操作是否有幂等键。
- 重试策略是否使用指数退避。
- 是否有熔断和降级逻辑。
- 日志是否脱敏,是否记录了外部链路ID。
- 监控是否有成功率和P99耗时指标。
- 告警是否配置了分级提醒。
- 是否有回滚方案,比如功能开关可以快速关闭该对接功能。
7.4 出问题时按什么顺序排查
| 排查顺序 | 检查对象 | 确认方式 |
|---|---|---|
| 1 | 请求是否真正发出 | 查看应用日志、网关日志 |
| 2 | 路径、域名、参数是否符合文档 | 对照接口文档逐项检查 |
| 3 | 鉴权是否通过 | 检查API Key、Token、签名是否有效 |
| 4 | 权限是否足够 | 检查IP白名单、接口权限、账号状态 |
| 5 | 服务端错误码 | 看响应body里的code和message |
| 6 | 网络和超时 | 抓包、tcpdump、nslookup、ping |
| 7 | SDK版本和依赖 | 查看库版本、ReleaseNote、服务端API版本 |
三年下来,我最深的一条体会是:API对接的质量不在对接当天,而在对接前怎么理解协议、对接中怎么留证据、上线后怎么快速定位。把这三件事做成清单,比记住任何一家平台的接口都重要。下次再遇到529 overloaded或者connection lost mid-response,先问自己有没有按顺序排查,而不是直接改代码重试,很多问题就不会浪费半天。
