如何调试您使用但并不拥有的 API。
如果API反馈出意想不到的结果,该怎么办呢?这个问题是出在用户输入、API本身,还是其他完全无关的方面呢?对于 API 用户来说,调试意味着识别和修复单个 API 调用或调用序列中的问题。在很多情况下,你正在调试的代码可能不受你的控制,并且受可观察对象的支配。除了在访问 API 时可能会遇到意想不到的行为外,你还可能在解析输出或传递变量时犯错。
在本文中,我们将深入探讨更快速、更可靠地调试 REST API 的方法和原则。
什么是API调试?
调试过程旨在了解输入和输出之间的关系。大部分工作都是根据可以观察到的情况来定位问题的根本原因。如果你将来自不同提供商或访问不同资源的一系列 API 调用串联在一起,这可能会变得很棘手。
理想情况下,你会拥有一个强大的测试和监控系统,可以在出现问题时向你发出警报,并指出问题所在。但即便你不具备这种可观察性,采用一致的方法也可以减少发现和解决问题所需的时间和精力。
以下是一种识别bug的方法:
- 隔离 API 问题
- 检查状态信息
- 更深入地检查数据
我将在 Postman 中演示这些调试示例,但你也可以使用自己喜欢的开发工具或 API 客户端。
隔离 API 问题
第一步是隔离 API 问题,并确定问题是源于调用 API、API 本身、处理输出,还是与之完全无关。在你最喜欢的开发工具或 API 客户端中重现这个问题,以便进行更深入的检查。这样你就可以更轻松地检查和调整请求参数、标头和正文,并与反馈进行比较。如果无法可靠地辨别输入和输出之间的关系,那么问题可能不在 API 调用本身。例如,可能是第三方服务或基础设施的变更导致了意外的状况。
在 Postman 等开发工具中重现问题,以便进行更深入的检查
如果要将 API 调用导入到 Postman中,可以粘贴 cURL 命令作为原始文本。您还可以使用代理采集一系列调用,以便重放或录制。
查看状态信息
当你与 API 对话时,服务器会返回一个 HTTP 状态代码,表示你的 API 请求的状态。状态代码和错误信息由 API 提供商决定,因此它们的意义和准确性各不相同。但大多数 API 提供商都遵循既定惯例,即使用状态代码的第一位数字来定义响应的类别。例如,状态代码为 400 表示客户端出现问题。这意味着你可以更新请求以潜在地解决该问题。状态代码为 500 表示服务器有问题。除了验证你访问的是正确的资源并稍后检查外,你能做的不多,除非你也是 API 提供商。
假设服务器反馈了可靠的状态信息,这是我们追踪bug源头的第一条线索。以下是一些常见的客户端错误代码,以及遇到这些错误时可以采取的措施:
400 错误请求: 查找语法错误,如错别字或错误的 JSON 主体。
401 未授权: 请确认您对目标资源是否有有效的身份验证凭据,并检查标题值的语法。
403 禁止: 检查您的权限和范围,以确保您有权访问该资源。
418 我是一个茶壶: 可能表示请求是提供商不想处理的请求,如自动查询。
429 请求太多: 查看文档以了解速率限制或稍后再试。
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响应,就可以使用句点点或括号符号访问属性,并在数组中循环。如果你试图访问复杂结构中的深层嵌套信息,可能需要逐步将其分解,以便精确地引用该信息,并确保不会深入到研究未定义的内容中。
- 身份验证与授权: 身份验证验证用户的身份,授权则确认用户拥有访问资源的权限。如果请求中包含了正确的授权标头,但仍无法访问资源,请再次仔细地检查与凭证相关的权限和范围。
- 内容类型标头: Content-Type 和 Accept 标头有助于客户端和服务器之间的内容协商。Content-type请求标头告诉服务器客户端发送的信息类型。另一方面,Accept请求标头告诉服务器客户端可以理解的内容类型。有些API需要特定的请求标头,并且只适用于与特定的内容类型配合使用。
对于这些常见错误,你可以依靠语法加亮显示、检查程序和其他检查功能来来提供更多的问题可见性。开发人员控制台还能为应用程序的网络调用和日志语句提供更多可见性,以便进一步帮助你隔离输入、输出以及从一个调用到另一个调用的数据传递问题。例如,如果你有一连串同步或异步调用序列,记录关键节点的值或设置条件断点可以帮助你快速定位问题。在整个调用执行过程中使用 console.log() 等控制台语句可以进一步验证解析输出的假设。
使用控制台来查看网络调用、调用执行顺序和变量值
调试策略的类型
有许多调试策略可以缩小问题原因的范围。这些策略大致可以分为三大类。
暴力破解策略
如果你对系统的可观察性有限,这意味着你需要调整和记录一切。在整个 API 调用序列的某些点添加策略性日志语句可能会有所帮助。然而,由于解释日志数据需要花费更多的时间,日志数量的收益正在递减。
回溯策略
这种策略是指从第一次观察到错误的点开始回溯,以找到根本原因。同样,你可以从显示您所期望的行为的 API 调用开始,然后逐步查看后续调用,直到找到bug为止。当你对可能导致问题的原因有了合理的假设时,这种策略就会很有效,但当错误远离根本原因时,这种策略就不那么有效了。
分而治之策略
在复杂的系统中,将系统分成较小的部分可以让你更容易发现问题。二分搜索就是这种策略的一个例子,你可以在较长的调用序列中间输入日志语句或断点。如果在断点处没有出现缺陷,则对下半部分的调用重复这一过程,依此类推。另一种策略是使用模拟服务器来隔离被测系统。你可以依靠模拟响应来实现外部依赖关系,或为你的方案提供一个起点。
进入调试思维模式
经过一段时间后,如果只关注了问题但并没有取得实质性的进展,可能会适得其反,因为你会”只见树木,不见森林”。以下策略可以帮助你获得更有效的调试思维模式。
- 橡胶鸭式调试: 向他人阐述问题和假设,这可能能够帮助你转换自己的视角,迫使你放慢速度,明确地陈述你的假设。
- 从集中模式切换到分散模式:切换到一种不同的活动,比如远足,这能够让你的大脑进入不同的状态。当你的大脑被动地建立新的连接,可能会产生创造性的见解,这就是分散的学习模式。这就是为什么你在洗澡时或刚睡醒时会有最好的想法的原因之一。
调试时省时省力又省心
无论你是刚接触 REST API,还是经验丰富的老手,采用一致且有条不紊的方法进行调试都能节省时间和心力。你所选择的调试策略取决于系统的可观察性。如果你的系统已通过预定义的日志和堆栈跟踪进行了广泛的监控,你就可以快速发现问题,并可能能够立即发现bug。如果没有这些措施,你可以简化问题以缩小搜索范围,并利用其中一些调试策略来提高可见性。