外部API失效时的REST API状态-最佳做法

时间:2019-11-22 12:26:31

标签: rest web-services http

我正在寻找有关从REST API返回错误的良好实践指南。我正在开发一个新的API,因此可以朝任何方向发展。

在我的情况下,客户端调用我的API,而该API在内部调用一些外部API。如果成功,没有问题,但是如果来自远端(外部云API)的错误响应,则我不确定此类服务的行业标准是什么。目前我正在考虑返回200 OK,然后返回一个json负载,其中详细说明了外部API错误。

那么行业的建议是什么?好的做法(请解释原因!),以及从客户端pov看,REST API中的哪种错误处理使客户端代码的工作变得更轻松?

4 个答案:

答案 0 :(得分:3)

您要询问的故障是服务本身内部发生的故障,尽管它具有外部依赖性,所以 5XX 状态代码范围是正确的选择。 503 Service Unavailable看起来非常适合您所描述的情况。

5XX代码用于告诉客户端,即使请求很好,服务器在执行请求时也会遇到一些问题。另一方面,

4XX代码用于告诉客户端它在请求中做错了什么(服务器很好,谢谢)。 Sections 10.4 and 10.5 of the HTTP 1.1 spec解释4XX和5XX代码的不同用途。

答案 1 :(得分:1)

我们的同事已经提供了有关HTTP状态代码的链接/说明,因此您应该学习它们并找到最适合您的情况。

假设您已经学会了状态码,我将更专注于会影响您决策的因素。

基本上,您应该了解客户端调用“您的” API时触发的流程的业务含义。客户端对您正在使用的外部云API一无所知,也不在乎它是否有效,客户端可以与您的应用程序一起使用。

如果是这样,当远程系统返回某种错误时(是的,不同的错误状态应该为您提供远程系统出了什么问题的线索),这是您如何处理此错误的业务决策,具体取决于您可能想在与客户的互动中以不同的方式“做出”这一决定。

以下是一些示例:

  1. 您知道远程系统很少中断。但是一旦它不可用,您的系统就无法正常运行。 在这种情况下,如果呼叫失败,您可以考虑重试对远程系统的呼叫。如果您仍然不走运,请返回一些错误状态。大概是5XX

  2. 您知道远程客户端提供的数据并不是很重要,另一方面,当客户端调用您的API时,即使它不是最新的,也最好提供“某些东西”。考虑一下通过某些客户端ID提供“推荐电影”的远程系统。并且您正在构建门户(netflix样式)。如果推荐的电影服务由于某种原因而关闭,则无法使整个门户页面失效(请考虑糟糕的用户体验)。在这种情况下,您可能希望“预缓存”一些电影的常规列表,并在该远程服务失败的情况下将其用作备用。在这种情况下,无论如何您都应该返回2XX状态。

  3. 更高级的体系结构。您知道远程服务经常会失败,并且当它关闭时您可以继续工作。在这种情况下,您可能希望选择与客户端交互的“异步”风格。例如:客户打电话给您休息,您立即以“已接受”状态代码(202)进行响应。您可以将此ID及其状态保存在某些数据库中,以便当用户“通过票证ID询问票证的状态”时,您将能够查询数据库。关键是您会立即返回。然后,您可能希望将带有任务的消息发送到某个消息传递系统,一旦使用者选择了该消息,便会对其进行处理并更新数据库。只要远程服务失败,该消息将返回队列,仍处于“未处理”状态(通常,消息传递系统可以实现此行为)。现在,在某个时间点,远程系统开始响应,并且所有消息都得到处理。现在,它们在数据库中的状态为“完成”。 因此,由客户问“发生了什么” /您可以使用Web套接字或其他东西(在这种情况下,不再是REST风格的通信)来实现某种推送模型。但要点是,在某个时间点,客户会收到“确定,我们已完成票证ID”(状态200)。在这种情况下,客户端可以调用特殊的端点并使用您还将存储在数据库中的存储结果(状态再次为200)

最重要的是,HTTP返回代码只是一个指示符,但是如何组织与客户端的互连过程以及相关HTTP状态取决于您,这取决于您的决定。

答案 2 :(得分:0)

HTTP调用在客户端和服务器之间,因此错误代码应反映该关系的任一侧上错误或错误所在的位置。仅仅因为它在您的下游并不意味着HTTP客户端需要关心它。

鉴于此,您应该返回5xx错误,因为故障不是客户端,服务器(或其下游服务)造成的。因为HTTP调用未成功,所以返回2xx(请注意以下内容)是不正确的,而返回4xx则是不正确的,因为这不是客户端的错误。

查看特定的5xx,您可以返回:

  • 如果您要特别表示您的服务正在充当网关/代理,则504或502可能是合适的。
  • A 523是unofficial but used by cloudflare,专门表示上游/原始服务不可达
  • 500(具有人机可读的错误体)是安全的默认值,它仅表示“服务器及其服务目前存在某些问题”。

现在,按照最佳实践,可以使用一些技术来减少500个错误,或者使客户端更轻松地对此5xx响应进行响应/反应。

  • 将重试放在您的服务中。如果您的服务正常工作并且故障在下游,并且可以成功存储客户端的请求,以便在下游服务可用时稍后重试,那么您仍然可以使用2xx进行响应,并且客户端知道他们的请求将被提交。一个很好的例子就是用户注册工作流程。您可以在自己身边进行注册,然后将欢迎电子邮件排队,如果您的电子邮件提供商不可用,请稍后重试。

  • 在API响应中同时包含人工描述,机器错误代码和链接。在根据服务进行调试和开发时,人工描述非常有用。机器代码意味着客户可以索引/跟踪和编码给定方案的特定代码路径,而链接到您的文档意味着您可以始终提供更多信息。更好的是包括任何特定的ID,以供您跟踪此错误的实例,以防HTTP客户端需要获得支持(尽管这在很大程度上取决于您的日志记录和遥测)。这是一个示例:

    {
        "error_code": 1234,
        "description": "X happened with Y because of Z.",
        "learn_more": "https://dev.my.app/errors/1234",
        "id": "90daa63b-f5ac-4c33-97d5-0801ade75a5d"
    }
    
  • 包括一个Retry-After标头,以便您的HTTP客户端知道在X时间之后才重试对您的垃圾邮件。这意味着您的错误流量更少,并且可以更好地为客户端进行请求计划。

答案 3 :(得分:0)

我将使用503-服务不可用-作为错误。原因-

  • 正在考虑以下情况:没有外部API的响应,API操作将无法完成。这类似于我的数据库没有响应。因此,在外部服务重新联机之前,我的API无法使用。
  • 作为API客户端,我不关心API服务器是否在内部调用其他API。我只关心API服务器的结果。因此,对我来说,我是否是代理服务器都无关紧要-因此,我将避免使用502(错误网关)和504(网关超时)。这些错误可能会使客户端错误地认为客户端和我们的服务之间的网关会引起麻烦。
  • 按照@developerjack的建议,我还建议-“包含一个Retry-After标头,以使您的HTTP客户端知道在X以后才对您进行垃圾邮件重发。这意味着您的错误流量减少了,并且更好地为客户请求计划。”