处理错误

简要概述

向服务发送 API 请求,可能会产生多种不同的错误响应,以下文档将会描述数据结构以及大致的原因。

在 gRPC 中,错误状态码是通过 google.golang.org/grpc/codes 包定义的,这些状态码遵循 gRPC 的官方规范。

响应体结构

查看完整的 proto 文件定义,关键部分如下:

// ErrorResponse 用于定义统一错误响应体
message ErrorResponse {
  Status error = 1;
}

// Status 用于定义统一错误状态码
message Status {
  int32 code = 1;
  string status = 2;
  string message = 3;
  repeated google.protobuf.Any details = 4;
}

一个 json 示例:

{
  "error": {
    "code": 5,
    "status": "NotFound",
    "message": "unknown service",
    "details": [
      {
        "@type": "type.googleapis.com/grpc_kit.api.known.status.v1.TracingRequest",
        "id": "b17f76dc51de4098bc974e5f2009c097"
      }
    ]
  }
}

状态码说明

codestatushttp codedefault message
0OK200No error.
1Canceled499Request cancelled by the client.
2Unknown500Unknown server error.
3InvalidArgument400Client specified an invalid argument.
4DeadlineExceeded504Request deadline exceeded.
5NotFound404A specified resource is not found, or the request is rejected by undisclosed reasons, such as whitelisting.
6AlreadyExists409The resource that a client tried to create already exists.
7PermissionDenied403Client does not have sufficient permission.
8ResourceExhausted429Either out of resource quota or reaching rate limiting.
9FailedPrecondition400Request can not be executed in the current system state, such as deleting a non-empty directory.
10Aborted409Concurrency conflict, such as read-modify-write conflict.
11OutOfRange400Client specified an invalid range.
12Unimplemented501The API method not implemented or enabled by the server.
13Internal500Internal server error.
14Unavailable503Service unavailable.
15DataLoss500Unrecoverable data loss or data corruption.
16Unauthenticated401Request not authenticated due to missing, invalid, or expired OAuth token.
204NoContent204Service is no additional content to send in the response content.

自定义状态码

标准 Code 的限制

  • codes 包中的状态码(如 OK、NotFound、Internal 等)是固定的枚举值,不允许扩展;
  • gRPC 协议规定客户端和服务端必须使用这些预定义的状态码(范围 0~16),其他值会被视为非法;
  • gRPC 多语言实现中依赖标准化的错误码,自定义会引起兼容性问题;
  • 如负载均衡、重试等组件有些已经依赖预定义码的语义,所以不可自定义。

自定义状态码实现

虽然不能新增 code,但可以通过以下方式传递额外信息:

  • Status 的详情信息(Details)

    使用 errs.xxx.WithDetails 附加 Protobuf 消息:

    errs.InvalidArgument(ctx).WithDetails(&errdetails.LocalizedMessage{Locale: "en-US", Message: "Field 'email' is invalid"})
    

    客户端可通过 status.FromError() 和 st.Details() 解析。

  • Metadata(头部信息)

    通过 grpc.SetHeader() 或 grpc.SendHeader() 传递自定义元数据(如错误子类型)。

  • 错误消息(Message)

    在的消息体中包含结构化信息(如 JSON),但需客户端手动解析。

    errs.InvalidArgument(ctx).WithMessage("EmptyRegion The specified account has no access authority to any region.")