API 调试实战手册:从抓包到合同校验

可重复的事故调试流水线:解析 URL、格式化响应、json-diff、JWT 检查与 schema 校验,全在浏览器本地完成。

· 全部指南

API 出问题时,先收集证据再猜原因

生产 API 故障很少只给一行清晰错误。可能是网关 502、200 却返回 {"success":false}、截断的 JSON、或「Postman 能过、App 不行」的 JWT。高效团队把调试当成可重复流水线:抓取请求 → 规范化响应 → 与已知良好版本 diff → 校验合同 → 再缩小到鉴权、路由或语义。

本 playbook 用 Towalles 浏览器本地工具走完该流程。操作不会把抓取内容上传到 Towalles 服务器——粘贴前仍须脱敏 Token 与客户字段。JSON 技巧见 json-formatting-guide;URL 边界见 url-api-debugging-guide

阶段一:抓取并解析请求

最小复现 — 一个失败端点、一种身份、一种 payload。记录 method、path、query、headers(脱敏 Authorization)与 body。

解析 URL — 将完整 URL 贴入 url-parser,确认协议、主机、路径段与解码后的 query。双重编码(%252F)与 query 里 + / 空格差异会导致客户端 SDK 静默不一致。

编码排查 — 参数乱码时,用 url-encoderbase64-encoder-decoder 检查编码叠加(JSON 里的 URL 编码再 Base64)。

在事故文档记录:「query filter 解码为空,因客户端发送了无值的 filter=。」

阶段二:规范化响应体

先格式化 — 压缩的错误 JSON 把真因藏在 error.details[0].message 深处。贴入 json-formatter。若解析失败,可能是 HTML 错误页、SSE 分片或截断 gzip——对照 Network 的 Content-Type 与 body 长度。

从 LLM 包装中提取 — AI 网关常返回 Markdown 代码块。正文混杂 prose 与 JSON 时,先用 llm-json-extractor 再格式化。

跨环境对比 — 保存 staging 与 production 响应(脱敏),分别格式化后用 json-diff 看路径级差异。常见发现:缺少 data.version、类型从 numberstring,导致移动端严格解析失败。

示例:

// staging
{ "user": { "id": 42, "tier": "pro" } }
// production
{ "user": { "id": "42", "tier": "pro" } }

仅格式化看不出 ID 类型变化;diff 可以。

阶段三:鉴权与 Token

401/403 或间歇失败时:

  1. Bearer Token 贴入 jwt-decoder(自动去掉 Bearer )。
  2. expnbfaudiss 与时钟偏差。
  3. 核对自定义声明(scoperoles)与路由策略。
  4. 牢记:解码不是验签——结合服务端日志查签名失败。

不透明 API Key 用 api-key-format-checker 识别厂商格式,确认未混用 test/live 前缀。若 live key 出现在工单附件,立即轮换。

hmac-generator 仅用于本地测试向量复现——勿粘贴生产签名密钥。

阶段四:合同与 Schema

语法合法的 JSON 仍可能违反 OpenAPI。格式化后:

  • structured-output-validator 对照 JSON Schema fixture。
  • openapi-formatter 查组件定义,确认字段在 spec 中存在。

CI 应长期做 schema 校验;事故中手动跑 validator 可区分「服务端漂移」与「客户端假设错误」。

配置驱动 API 时,用 yaml-converter 转换部署 YAML,格式化后与上一版 json-diff(思路同 yaml-toml-config-guide)。

阶段五:时间、Cron 与幂等

定时任务失败?用 cron-validator 校验表达式(参见 cron-scheduling-guide)。差一小时时区会让批量窗口错位,看起来像「随机」API 故障。

重试风暴时检查幂等键(常为 UUID)——用 uuid-generator / ulid-generator 生成测试 ID,并在 API 目录记录期望 header 名。

阶段六:沟通与收尾

事故评论模板

  • 请求:method、path、query 摘要(无密钥)
  • 响应:status、错误路径格式化摘录
  • Diff:相对上次良好版的变化
  • 鉴权:exp/aud/iss 摘要(无 raw token)
  • 下一负责人:后端 / 网关 / 客户端

事后 — CI 增加 fixture、runbook 链到 json-formatting-guide、轮换已暴露凭证。

工具链速查

现象 首选工具 接着
Query 乱码 url-parser url-encoder
JSON 难读 json-formatter json-diff
发布后 401 jwt-decoder 服务端验签日志
JSON 合法但形状错 structured-output-validator OpenAPI diff
聊天里的 webhook llm-json-extractor json-formatter
配置回归 yaml-converter json-diff

浪费时间的坑

  • 在共享标签用 live refresh token 调试生产。
  • 以为「能格式化」就等于服务端发了合法 JSON(代理可能改写 body)。
  • 忽略 Content-Encoding 与双重解析字符串。
  • 不做 diff——肉眼扫 200 行对象找一处字段变更。

Towalles 工具页会链到专题指南;本 playbook 把它们串成事故可用顺序。下次 SEV-2 前收藏 api-debugging-playbook,按阶段执行再谈「是不是缓存问题」。

附录:完整示例(合成数据)

现象 — 网关发布后移动端登录失败;Postman 同 bearer 返回 200。

阶段一url-parser 解析 https://api.example.com/v2/users/me?fields=profile,settings,确认路径 /v2/users/me(网关新增 /v2 剥离规则)。

阶段二json-formatter 格式化移动端错误体:

{"error":{"code":"PROFILE_SHAPE","details":[{"path":"user.id","expected":"number"}]}}

阶段三jwt-decoderexp 有效;audmobile-app;非鉴权问题。

阶段四json-diff 对比 staging/production 的 user → production id 在序列化变更后变为 string。

解决 — 后端 hotfix 强制 number;用 structured-output-validator 加 schema 测试;runbook 链到 api-debugging-playbook

按序用工具相对随机 grep 日志,跨团队事故通常可省 30–90 分钟。

附录:状态码路由表

HTTP 状态 首要假设 Towalles 第一步
400 body/query malformed json-formatterurl-parser
401 Token 缺失/无效 jwt-decoder
403 scope/角色不符 jwt-decoder 声明 + 策略文档
404 路径/版本漂移 url-parser + 部署 diff
409 幂等冲突 uuid-generator 测 header
422 Schema 校验失败 structured-output-validator
429 限流 少靠工具——查 retry-after
502/504 网关/上游 仍抓取 body;可能是 JSON 错误包装

附录:curl → Towalles 交接

curl -sS -D - https://api.example.com/health -o /tmp/body.json

/tmp/body.json 复制到 json-formatter;响应头写入事故文档(脱敏 cookie)。勿把 live token 写进 shell history——用事后清除的环境变量。

curl 负责传输、Towalles 负责检视,符合 choosing-local-online-tools 的混合模式。

阶段六:GraphQL 与嵌套错误

GraphQL 常返回 HTTP 200,同时带 errors[] 与部分 data。用 json-formatter 格式化全文后检查:

  • errors[].path — 哪个字段失败
  • errors[].extensions.code — 鉴权 / 校验 / 内部错误
  • data 是 null 还是半填充(客户端两种都可能抛)

对比 staging/production 时,用 json-diff 只 diff data 子树——错误噪声每次 request ID 都变。合同严格时用 structured-output-validator 校验 persisted query 与 variables JSON。

Authorization 头里的 JWT 仍应先 jwt-decoder——过期 token 常被包装成含糊的 GraphQL 错误。

阶段七:CORS、预检与「Postman 能通」

Postman 与 curl 忽略浏览器 CORS。SPA 失败但 curl 成功时:

  1. 确认失败请求来自浏览器 origin(DevTools)。
  2. 在 Network 里看 OPTIONS 预检响应头——不只看 GET/POST。
  3. 若错误是不透明的 TypeError: Failed to fetch,可能没有 JSON 可格式化——记为 CORS/网络类失败,而不是 json-formatter 里的 400。

工单中勿粘贴含 Cookie 的完整 Access-Control-*;脱敏 Set-Cookie

阶段八:流式、SSE 与截断 body

SSE 与 chunked 响应在 json-formatter 里常像「坏 JSON」,因为你只抓了一个 event。先按 data: 行拆分,再逐条格式化。网关 body 上限截断会在字符串中间报错——重写 parser 前先对比 Content-Length 与实际字节。

若从流事件抽出 JWT,用 jwt-decoder;用 token-counter 估 LLM prompt 前先经 pii-scanner 脱敏。

阶段九:幂等与重放

409/425 与重复扣款需要关联 ID。用 uuid-generatorulid-generatorIdempotency-Key 生成新测试键;调试时勿在重试中复用生产键。把 key 记入事故文档;本应幂等相同的两次响应用 json-diff 对比。

Runbook 片段:前十五分钟

T+0   单身份复现;记下 request ID
T+3   url-parser 解析完整 URL;脱敏 Authorization
T+6   json-formatter 看响应(或注明 HTML/SSE)
T+9   疑似鉴权则 jwt-decoder
T+12  疑似形态问题则 json-diff staging vs prod
T+15  疑似合同问题则 structured-output-validator

把这张卡连同 api-debugging-playbookurl-api-debugging-guide 交给新值班工程师。

相关工具