HTTP status 与自定义 code 的最佳实践
2023/03/04 · vran

在 API 开发或对接中,经常会看到协议中有自定义 code 的设计

  • 那为什么要这么设计呢?
  • 这种设计有没有什么实践?
  • 大厂都是怎么做的呢?

跟随本文,一起揭晓以上问题

为什么还要自定义 code?

HTTP 协议中定义了 5 类 status code

  1. Informational responses(100199)
  2. Successful responses(200299)
  3. Redirection messages(300399)
  4. Client error responses(400499)
  5. Server error responses(500599)

这其中留给开发者可以用的 status code 少之又少,而实际的业务响应又会有非常多的状态,所以开发者需要一种方式来扩展 code。

这其中最直观的方式就是定义一个标准的响应结构,这个结构中有着一个自定义的 code 字段,它可以用来表示业务的响应状态,如下:

{
    "code":"A1000",
    "message":"会员已过期"
}

所以,自定义 code 本质上是对 status code 的一个扩展,是为了满足实际业务中复杂的状态表达而设计的。

自定义 code 该怎么用?

HTTP 的 status 不够用导致我们设计了自定义 code,但现在很多 API 的 code 都已经被滥用了。

我推荐的做法是:按语义将 HTTP status 当作一级分类,自定义 code 当作二级分类

  • 2xx 请求成功
  • 4xx 客户端错误,不影响服务可用性
  • 5xx 服务端错误,影响服务可用性

Untitled

2xx 代表成功,实际业务场景下很少会碰到成功之下还要再区分不同的成功状态的,即使遇到了,设计一个更符合业务语义的字段通常也会更好。

所以, 2xx 的响应没必要设置自定义 code

Untitled

而 4xx、5xx 这种错误响应之下再做错误细分的场景是很常见的,比如 4xx 客户端错误之下需要明确具体的业务错误:支付时用户余额不足、商品库存不足、支付超时等。

Untitled

现在明确了只为 4xx、5xx 扩展 code,而 code 又是由响应体来承载的,接下来就看看如何设计错误响应体。

错误响应体怎么设计?

先来看看微软在它的 REST API guidlines 里的设计

https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#errorresponse–object

{
  "error": {
    "code": "BadArgument",
    "message": "Multiple errors in ContactInfo data",
    "target": "ContactInfo",
    "details": [
      {
        "code": "NullValue",
        "target": "PhoneNumber",
        "message": "Phone number must not be null"
      },
      {
        "code": "NullValue",
        "target": "LastName",
        "message": "Last name must not be null"
      },
      {
        "code": "MalformedValue",
        "target": "Address",
        "message": "Address is not valid"
      }
    ]
  }
}

GITHUB 在其 REST API 平台上也有示例

https://docs.github.com/en/rest/overview/resources-in-the-rest-api?apiVersion=2022-11-28#client-errors

{
   "message": "Validation Failed",
   "errors": [
     {
       "resource": "Issue",
       "field": "title",
       "code": "missing_field"
     }
   ]
 }

这里的 code 可以分为以下几类

Error code name Description
missing A resource does not exist.
missing_field A required field on a resource has not been set.
invalid The formatting of a field is invalid. Review the documentation for more specific information.
already_exists Another resource has the same value as this field. This can happen in resources that must have some unique key (such as label names).
unprocessable The inputs provided were invalid.

从 GITHUB 和微软的设计上我们可以得出一些规律

  • code 是可读的
  • 通常也会包含一个详细描述的 message 字段
  • 根据响应,调用方有能力定位到导致错误的资源(字段)
over