通过微服务传播错误的良好实践

Good practices to propagate errors through micro services

我们有一个微服务架构,我们正在讨论如何将内部错误暴露给客户端。

这是一个例子:

假设我们有 3 个服务,服务 A、B 和 C。 当客户端向服务 A 发送请求时,即 public,该服务向服务 B 发送请求,服务 B 向服务 C 发送请求(这是内部的,需要身份验证,但凭据像环境一样存储在内部变量,它们不是由客户端发送的)。

并且出于某种原因,B 和 C 之间的通信收到 401(可能是 422、403 或任何与客户端相关的错误),这意味着请求未被授权。

类似的东西:

B和C之间的通信是内部的,用户不知道这些服务。我应该公开我们的内部结构并向客户端发送 401 吗?鉴于这不是客户的错?我应该发送 500 吗?

最好避免显式公开 500 状态,但在某些情况下这是必要的。用户使用你的系统而不是特定的服务,对他来说,里面有什么并不重要。内部系统实施可能会有所不同,但用户交互可以保持不变。

假设 A 是电子商务服务,B - 计费服务,C - 计费网关。用户通过 A 购买产品,A 向 B 发送计费请求,B 与 C 通信以执行交易。 B 和 C 之间的 401 可能出于不同的原因。如果它只是内部配置问题(没有更新密码,过期证书等),它是一个内部系统错误,你需要告诉用户服务现在不可用或类似的东西,当然不要传递所有内部错误细节。在这种情况下,您可以使用 5xx 代码。也许服务 B 可以将请求放入某种队列并告诉服务 A 一切正常,您的请求将在稍后处理。但如果是因为用户尝试使用不良信用卡或没有足够的钱(未授权请求),则需要显示正确的消息和 4xx 响应代码。

一般来说,一个服务暴露的是资源,而不管它背后有多少内部或外部服务、数据库、数据源等等。也许 B 和 C 之间的 401 意味着 B 去 D 服务(C 备用),而 A 服务根本不应该知道 401。因此,这取决于您需要向用户公开什么以及您需要如何处理不同的情况。

你的图表没有什么意义。在调用所有内部服务后,在成功 return 到用户之前,来电不是 200。

如果 B 和 C 之间的身份验证是内部的(服务器到服务器的身份验证),那么你有一个内部错误,502 是 return 到 A 的明智选择。当然,你可能会决定在服务器 A 中重试,因为您从 B 获得了 502,但这毫无意义,因为它是一个过期的令牌。因此,您可能会决定将内部 401 升级回 A 作为策略。或者您可能会发现在 502 错误响应正文中附加元数据有助于重试机制。无论如何,服务器-服务器身份验证不应该在有效调用的地方失败。

所以...如果 C 的身份验证在用户提供的令牌上工作,则用户的身份验证 运行 在调用期间失败(很少见,但会发生)- 在这种情况下,令牌应该扩展到其他地方在此调用之前的系统中(可能是在 A 对 SSO 的调用中)。但它不是,所以 return 401 到应用程序中的任何地方重定向到登录页面。