REST API 消费端的最佳调试实践

REST API 消费端的最佳调试实践
原文标题:Debugging best practices for REST API consumers.
原文链接:https://stackoverflow.blog/2022/02/28/debugging-best-practices-for-rest-api-consumers/#:~:tex
作者:Joyce Lin

当你调用的 API 返回意料之外的结果时,你会怎么做?调用出错可能是用户输入、API 本身或者原因导致的。对于 API 消费者(调用者),调试意味着识别和修复单个或多个 API 的调用问题。在很多情况下,你正在调试的可能是你无法查看或修改的代码,并且可观察到的内容也有限。除了在访问 API 时遇到意外行为外,你在解析输出或传递变量时也可能会出错。 如何在受限情况下调试 REST API 呢?

在本文中,我们会深入探讨更快速、更可靠地调试 REST API 的方法和原则。

什么是 API 调试?

调试过程是为了解输入和输出之间的关系。调试的大部分工作都在根据可观察到的情况定位根因。如果你将来自不同服务端或者不同资源访问的一系列 API 调用串在一起,调试就变得更加棘手。 理想情况下,你有一个强大的测试和监控系统,可以在出现问题时提醒你并查明问题可能出在哪里。但即使你没有,你也可以通过以下方法来减少查找和修复问题所需的时间和精力。 这里展示的是一些识别错误的方法:

  • 隔离 API 问题
  • 检查状态消息
  • 更深入地检查数据

隔离 API 问题

第一步是隔离 API 问题并确定问题是否源于调用 API、API 本身、处理输出或完全不相关的问题。在你最熟悉的开发工具或 API 客户端中重现该问题以进行更深入的检查。这样你可以更轻松地检查和调整请求参数、Header 和body ,然后与响应结果进行比较。如果你无法准确地判断输入和输出之间的关系,则问题可能不在 API 调用本身。例如,可能存在第三方服务或基础架构变更导致的意外行为。

              (在开发人员工具(如 Apifox )中重现该问题以进行更深入的检查)

译者注:与原文使用 Postman 演示不同,为便于中国开发者本地化体验,本篇译文中演示部分将使用 Apifox 进行,你可以自由选择你熟悉的开发工具或 API 客户端。

检查状态码

当你与 API 服务端对话时,服务器会返回一个 HTTP 状态码,表明你的 API 请求的状态。状态码和错误消息由 API 服务端给出,因此它们的意义和准确性各不相同。但是大多数 API 提供者都遵循使用状态码的第一位数字定义响应类别的既定惯例。例如,400 中的状态代码表示客户端问题。这意味着你大概率可以通过更新请求来解决问题。500 中的状态码表示服务器问题。除了验证你正在访问正确的资源并稍后再回来检查之外,除非你也是 API 提供者,否则你无能为力。假设服务器返回可靠的状态消息,这是我们追踪错误来源的第一条线索。以下是 400 中的一些常见客户端错误码,以及时你可以采取的措施:

  • 400 Bad Request:查找语法错误,例如拼写错误或格式错误的 JSON 正文。
  • 401 Unauthorized:验证你是否具有目标资源的有效身份验证凭据,并检查 header 的语法。
  • 403 Forbidden:检查你的权限和范围以确保你有权访问该资源。
  • 418 I'm a Teapot:可能表示请求是提供者不想处理的请求,例如自动查询。
  • 429 Too Many Requests::查看文档以了解速率限制或稍后重试。

                                 (HTTP 状态码 400 表示客户端存在问题)

更深入地检查数据

下一步是深入挖掘并验证你的假设。你可以验证你是否已正确格式化每个请求并正确解析每个响应。当你沿着一系列 API 调用传递数据时,你还可以验证是否正确定义和引用了变量。以下是处理 HTTP API 时的常见问题:

  • 格式错误的 JSON新手在发送 JSON 正文时会犯一些常见错误。单引号在 JSON 字符串中无效,因此请确保用双引号将字符串和属性名称括起来。此外,JSON 不支持注释,因此要么缩小它们,要么别添加它们。
  • 序列化数据: REST API 经常将数据作为 JSON 对象存储和发送。为了正确传输数据,请确保使用 JSON.stringify() 对数据进行编码并使用 JSON.parse() 对其进行解码。。此外,服务器可能要求你设置Content-Type值为application/json。经过进一步检查,如果你看到类似[object Object]Unexpected token之类的值,则表明序列化和反序列化不正确。
  • 类型转换:当你准备发送请求或解析响应时,可以将值从一种类型转换为另一种类型。根据编程语言的不同,对字符串执行数学计算可能会失败,但将值转换为数字类型可以让你正常使用数据。
  • 提取信息:使用 JSON.parse() 反序列化 JSON 响应后,你可以使用点或括号表示法访问属性并循环遍历数组。 如果你试图访问复杂结构中深层嵌套的信息,你可能需要逐步将其分解以精确引用该信息并确保你不会试图更深入地钻探未定义的内容。
  • 身份验证与授权:身份验证是用来确认用户是否是他们所声明的人,而授权是用来确认用户有权访问资源。如果你在请求中包含正确的授权 Header 但仍然无法访问资源,请仔细检查与你的凭据关联的权限和范围。
  • 内容类型标头: Content-Type 和 Accept 请求头有助于客户端和服务器之间的内容协商。 Content-type 告诉服务器从客户端发送的信息类型。 另一方面,Accept 告诉服务器客户端可以理解什么类型的内容。 某些 API 需要特定的请求标头并且仅适用于特定的内容类型。

对于这些常见错误,你可以依靠语法高亮、linter 和其他检查功能来提升问题的可见性。控制台还可以提供对应用程序网络调用和日志语句的更多可见性,以进一步帮助你隔离输入、输出和从一个调用到另一个调用的数据传递问题。 例如,如果你有一系列同步或异步调用,记录关键连接处的值或设置条件断点可以帮助你快速查明问题。 在整个调用执行过程中使用诸如 console.log() 之类的控制台语句可以进一步验证你对解析输出的假设。

                                            (使用控制台查看环境变量值)

调试策略的类型

许多调试策略可以缩小问题的原因范围。这些策略分为三大类:

蛮力策略

如果你对系统了解得不够,这意味着你需要调整和记录所有事情,通过大量枚举试错去达到调试的目的。在 API 调用序列的某些节点添加关键日志语句可能会有帮助。但随着解读日志数据所需时间的增加,日志量的收益也会逐渐降低。

回溯策略

该策略是指从第一次观察到错误的点向后移动以找到根本原因。同样,你可以从显示预期行为的 API 调用开始,然后逐步执行后续调用,直到找到错误。当你对可能导致问题的原因有合理的假设时,此策略很有效,但当错误与根本原因相去甚远时,此策略效果并不好。

分解策略

在复杂的系统中,将系统分成更小的部分可以让你更容易地发现问题。 二分搜索法是这种策略的一个示例,你可以在较长的调用序列中间输入日志语句或断点。如果该断点没有出现缺陷,则对后半部分调用重复该过程,依此类推。另一种策略是使用 mock 服务器来隔离被测系统。你可以依靠 mock 响应来屏蔽外部依赖项,从而为你的调试提供起点。

进入调试心态

调试一段时间后,只见树木不见森林,对一个问题钻牛角尖可能会适得其反。 以下策略可以帮助你进入更有效的调试思维模式。

  • 讲述型调试(橡皮鸭调试):向其他人(橡皮鸭)阐明问题和假设可能会迫使你放慢速度并明确陈述你的假设,从而改变你自己的观点。
  • 从集中模式切换到发散模式:完全切换到不同的活动,比如跑步,让你的大脑进入不同的档位。分散学习模式是指你的大脑被动地建立新的联系并可能产生创造性的见解。这就是为什么你在洗澡时或第一次醒来时,会突然灵感爆发的原因之一。

调试时节省时间和精力

无论你是使用 REST API 的新手还是经验丰富的老手,一致且有条不紊的调试方法可以节省时间和避精力。你选择的调试策略取决于系统的可观察性。如果你的系统使用预定义的日志和堆栈跟踪进行了广泛的监控,你可以快速发现问题并可能立即发现错误。如果这些措施没有到位,你可以简化问题以减少搜索区域并利用其中一些调试策略来定位根本原因。

订阅
qrcode

订阅

随时随地获取 Apifox 最新动态