接口调不通?按这个顺序排查

开发与 Web发布于 2026-10-31

前端报「接口 500」、后端说「我这边是好的」——这类对话的根源通常是两边发的请求不是同一个。

排查的顺序比经验更重要。下面这个顺序是从「最容易被忽略」到「最少见」排的,走一遍通常五分钟内能定位。

第 0 步:先把请求固定下来

在请求能复现之前,任何猜测都是浪费。最快的办法是拿到一条 curl 命令,它是请求的完整快照:方法、URL、全部请求头、body 原文。

在浏览器里:打开开发者工具 → Network → 右键请求 → Copy → Copy as cURL。

有了 curl,就能在终端里反复试,一次只改一个变量。想看请求和响应的完整结构(尤其是被折叠的长 JSON),用 JSON 格式化 展开,比在终端里瞪着眼睛找括号快得多。

第 1 步:Content-Type 对不对

这是最高频的原因,因为它的失败方式很矛盾:服务器返回 200,但收到的是空对象。

# 发 JSON 但没声明类型
curl -X POST https://api.example.com/user -d '{"name":"张三"}'

# 正确
curl -X POST https://api.example.com/user \
  -H 'Content-Type: application/json' \
  -d '{"name":"张三"}'

第一种写法,很多服务端框架会把 body 当成表单(application/x-www-form-urlencoded)解析,于是 name 变成一个名为 {"name":"张三"} 的键、值为空 —— 业务层拿不到 name,返回「缺少参数」。

注意 curl 的 -d 默认就是表单类型,JSON 必须显式加头。

第二常见的是表单 vs JSON 混用:前端 qs.stringify 之后忘了改头,或者后端只解析 multipart/form-data。

第 2 步:鉴权头带没带、带对没带

-H 'Authorization: Bearer eyJhbGciOi...'

三个细节:

  • Bearer 后面一个空格,大小写敏感(规范要求,多数服务端严格匹配)
  • token 前后不能有引号、不能有换行(从聊天窗口复制常带入不可见字符)
  • Authorization 不能和 Cookie 混着用,有些网关优先认 Cookie

JWT 之类的 token 出问题时,先解析看 exp 有没有过期、iss/aud 对不对 —— JWT 解析 可以本地解码三段并检查过期时间,不用把 token 贴到第三方站点。

如果是 401,问题在「你是谁」;如果是 403,问题在「你能不能」。这两个别混,见HTTP 状态码那篇。

第 3 步:CORS —— 只影响浏览器,不影响 curl

这条最容易误判:curl 通了、Postman 通了,浏览器不通,报 blocked by CORS policy。

原因:CORS 是浏览器的安全策略,服务端不参与拦截,它只是「不给你放行的响应头」。所以命令行永远不受影响。

排查要点:

  1. 非简单请求(自定义头、Content-Type: application/json、PUT/DELETE)会先发 OPTIONS 预检。
  2. 预检失败说明服务端没处理 OPTIONS,或者没返回 Access-Control-Allow-Headers。
  3. 带 Cookie 的请求需要 Access-Control-Allow-Credentials: true,且 Allow-Origin 不能是 *,必须回显具体来源。
  4. 报错信息里的响应头是给浏览器看的,实际响应体可能完全正常。

网关层(Nginx、Cloudflare)拦截 OPTIONS 也是常见情况 —— 直接 curl 一个 -X OPTIONS 请求看返回什么。

第 4 步:参数编码

GET 请求的参数如果含中文、&、+,不编码就会错位:

# 错:& 被当成参数分隔符
curl 'https://api.example.com/search?q=a&b'

# 对
curl -G 'https://api.example.com/search' --data-urlencode 'q=a&b'

--data-urlencode 是 curl 里最实用的参数之一:它按 UTF-8 编码并自动处理 &、+、空格。手写 %E4%B8%AD 很容易编错,规则见URL 编码那篇。

第 5 步:超时、重试与幂等

「偶发失败」通常是超时。默认超时可能长达几分钟,而网关 30 秒就断,于是前端看到的是 502/504,后端日志里请求还在跑。

curl --max-time 10 -H 'Content-Type: application/json' -d '{...}' https://api.example.com/x

同时确认:这个接口能不能重试?GET 天然幂等;POST 创建订单重试会重复下单。真正要重试的写操作,需要服务端支持幂等键(Idempotency-Key)。

把 curl 变成代码

调通之后要落进项目里,手写一遍 HTTP 客户端代码既慢又容易漏头。把 curl 粘进 cURL 转代码,可以直接生成 fetch / axios / Python requests / Go / Java 等写法,请求头和方法都带着,减少「本地能跑、线上少一个头」这类问题。

生成的代码仍然要自己检查:超时、错误处理、token 刷新这些 curl 里表达不了的东西,需要补上。

需要交互式地改参数、看响应头、保存多套环境变量,用 API 测试器 更顺手,支持自定义方法、头、body 和响应格式化。

一份排查表

现象 先查
200 但返回空对象 Content-Type
400 缺少参数 参数编码、body 格式
401 Authorization 头格式、token 过期
403 权限、IP 白名单、WAF
404 路径大小写、末尾斜杠、网关重写规则
405 方法不对(PUT vs POST)
413 body 超过网关限制
429 限流,看 Retry-After
502 / 504 网关等不到后端,看超时设置
浏览器 blocked by CORS 预检、Allow-Origin、Credentials

把这张表贴在调试时能看见的地方,比在聊天窗口里问「我这边 500 是什么原因」有效得多。


最后一句:curl 是唯一可信的事实来源。前端框架、代理、浏览器插件都可能在中间改请求,只有一条 curl 能让你确认「发出去的东西到底长什么样」。