错误处理(Error handling)
解释了 gRPC 如何处理错误以及 gRPC 错误代码。
标准错误模型
正如您在我们的概念文档和示例中所见,当 gRPC 调用成功完成时,服务器会返回一个 OK
状态给客户端(根据使用的语言,OK
状态可能会或不会在您的代码中直接使用)。但如果调用不成功,会发生什么呢?
如果发生错误,gRPC 会返回一个错误状态代码,并可附带一个字符串错误信息,提供有关发生问题的更多细节。错误信息对所有支持的语言的 gRPC 客户端都是可用的。
更丰富的错误模型
上述错误模型是官方的 gRPC 错误模型,所有 gRPC 客户端/服务器库都支持,并且与 gRPC 数据格式(无论是协议缓冲区还是其他格式)无关。您可能已经注意到,这个模型非常有限,不能传递错误的详细信息。
然而,如果您使用协议缓冲区作为数据格式,您可能希望考虑使用 Google 开发并使用的更丰富的错误模型,如 此处 所述。该模型使得服务器能够返回并允许客户端消费额外的错误细节,这些错误细节作为一个或多个 protobuf 消息进行表达。它进一步指定了 一组标准的错误消息类型,涵盖最常见的需求(例如无效的参数、配额违规和堆栈跟踪)。这些额外的错误信息的 protobuf 二进制编码会作为响应的尾部元数据提供。
这种更丰富的错误模型已经在 C++、Go、Java、Python 和 Ruby 库中得到支持,并且至少 grpc-web 和 Node.js 库已经公开了请求此功能的相关问题。其他语言库如果有需求,未来也可能会添加支持,因此如果您感兴趣,可以查看它们的 GitHub 仓库。然而,请注意,gRPC-core 库(用 C 语言编写)可能永远不会支持它,因为它故意保持数据格式独立。
如果您不使用协议缓冲区,也可以采用类似的方法(将错误细节放入尾部响应元数据中),但您可能需要找到或开发库支持来访问这些数据,以便在您的 API 中实际使用它。
在决定是否使用这种扩展错误模型时,有一些重要的考虑事项,包括:
-
扩展错误模型的库实现可能在语言之间对于错误细节负载的要求和期望不一致。
-
现有的代理、日志记录工具和其他标准 HTTP 请求处理程序无法看到错误细节,因此不能利用它们进行监控或其他用途。
-
尾部的额外错误细节会干扰行头阻塞,且由于缓存失效频繁,会降低 HTTP/2 标头压缩效率。
-
较大的错误细节负载可能会超出协议限制(如最大头部大小),导致原始错误信息丢失。
错误状态代码
gRPC 会在各种情况下引发错误,从网络故障到未经身份验证的连接,每种情况都与一个特定的状态代码相关。以下是所有 gRPC 语言中支持的错误状态代码。
一般错误
情况 | 状态代码 |
---|---|
客户端应用程序取消了请求 |
|
服务器返回状态之前,截止日期已过 |
|
服务器上未找到方法 |
|
服务器正在关闭 |
|
服务器抛出了异常(或执行了其他操作,而不是返回状态代码来终止 RPC) |
|
网络故障
情况 | 状态代码 |
---|---|
截止日期过后没有传输任何数据。也适用于传输了一些数据,但在截止日期过后没有发现其他故障的情况 |
|
在连接中断之前传输了某些数据(例如,请求元数据已写入 TCP 连接) |
|
协议错误
情况 | 状态代码 |
---|---|
无法解压缩但支持的压缩算法 |
|
客户端使用的压缩机制不被服务器支持 |
|
达到流控资源限制 |
|
流控协议违规 |
|
返回的状态解析错误 |
|
未经过身份验证:凭证未能获取元数据 |
|
在授权元数据中设置了无效的主机 |
|
解析响应协议缓冲区时出错 |
|
解析请求协议缓冲区时出错 |
|
语言支持
提供了多个语言的示例代码,说明如何处理标准错误以及如何处理更丰富的错误详情。
语言 | 示例 |
---|---|
C++ |
C++ 错误处理示例 |
C++ 错误详情示例 |
|
Go |
Go 错误处理示例 |
Go 错误详情示例 |
|
Java |
Java 错误处理示例 |
Java 错误详情示例 |
|
Node |
Node 错误处理示例 |
Python |
Python 错误详情示例 |
grpc-errors 仓库还包含了更多的错误处理示例。