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

Posted

技术标签:

【中文标题】通过微服务传播错误的良好实践【英文标题】:Good practices to propagate errors through micro services 【发布时间】:2017-11-20 11:32:55 【问题描述】:

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

这是一个例子:

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

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

类似的东西:

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

【问题讨论】:

如果不是用户的错,那么 5xx 是正确的响应码范围。 @OliverCharlesworth 我同意你的观点,我应该在内部记录这个错误并且不向用户公开任何信息吗?你怎么看? 视情况而定。但通常认为向用户公开内部错误详细信息(如堆栈跟踪)是不好的(从 UX 和安全角度来看)。最多只有一些消息,例如“500 服务器错误 - 您的唯一错误 ID 是 123456”,它允许您稍后将用户与错误日志中的 ID 相关联。 【参考方案1】:

您的图表毫无意义。呼入不是200,直到成功返回给用户,所有内部服务都被调用后。

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

所以......如果 C 的身份验证正在处理用户提供的令牌,那么用户的身份验证在调用期间用完(很少见,但会发生) - 在这种情况下,令牌应该在此之前在系统中的其他地方扩展呼叫(可能在 A 对 SSO 的呼叫中)。但事实并非如此,所以在应用程序重定向到登录页面的任何地方返回 401。

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

以上是关于通过微服务传播错误的良好实践的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud 微服务设计与实践

Netflix Feign - 通过微服务传播状态和异常

在微服务之间传播访问令牌

干货 | 特定企业微服务架构落地的研究与实践

.NET Core开发实战 微服务架构最佳实践

个推微服务网关架构实践