从此
📄文章 #️⃣专题 🌐酷站 👨‍💻技术 📺 📱

🏠 » 📄文章 » 内容

 欢迎来访!

HTTP API 错误 ERROR 响应标准 RFC 9457 为网站开发的巴别塔添砖加瓦

🕗2025-01-29👁️3

1. 背景

HTTP(Hypertext Transfer Protocol) API 成为了构建现代 Web 应用程序和移动应用程序的常用选择,因为它简单、灵活且易于理解。

对于正常响应,网络上有无数的文章讲过,不赘述。但是对于返回错误信息,并没有形成共识。以下是一些常见的做法:

  • HTTP 状态码(HTTP Status Code):使用标准的 HTTP 状态码来表示请求的处理结果。常见的状态码有:
  • 2xx 成功:表示请求被成功处理,如 200 OK 表示成功返回请求的内容。
  • 4xx 客户端错误:表示客户端发送的请求有问题,如 400 Bad Request 表示无效的请求。
  • 5xx 服务器错误:表示服务器在处理请求时发生错误,如 500 Internal Server Error 表示服务器内部错误。

通过适当选择合适的状态码,可以清楚地表示请求的结果和错误的类型。

  • 响应主体(Response Body):除了使用状态码,还可以在响应的主体中包含详细的错误信息。可以使用 JSON 或其他格式来构造错误响应体,其中包含有关错误的更多信息,如错误代码、错误消息、错误描述等。通过在响应主体中提供详细的错误信息,客户端可以更好地理解发生的错误,并采取适当的处理措施。 例如,对于 400 错误,可以返回如下的 JSON 格式的错误响应体:
{
    "error":{
        "code":400,
        "message":"Invalid request",
        "details":"The request body is missing a required parameter."
    }
}

举几个常用的状态码及其意义的例子:

状态码 状态名 建议场景
200 OK 成功
201 Created 资源被创建
400 Bad Request 请求参数不合法
401 Unauthorized 未登录或登录失效
403 Forbidden 没有访问权限
422 Unprocessable Entity 请求体验证错误
500 Internal Server Error 服务器发生错误

今天讨论的重点是响应主体的格式,它可是百花齐放的,举几个业界例子:

1.1. Amazon SP-API

来源: https://developer-docs.amazon.com/sp-api/docs/response-format#error-response

{
    "errors":[
        {
            "message":"Access to requested resource is denied.",
            "code":"Unauthorized",
            "details":"Access token is missing in the request header."
        }
    ]
}

Amazon 这个 API 返回的是错误对象数组,可以支持返回多个错误。

1.2. Azure REST API

来源: https://github.com/microsoft/api-guidelines/blob/vNext/azure/Guidelines.md

{
    "error":{
        "code":"InvalidPasswordFormat",
        "message":"Human-readable description",
        "target":"target of error",
        "innererror":{
            "code":"PasswordTooShort",
            "minLength":6
        }
    }
}

Azure 这个 API 在发生错误的时候,返回一个 ErrorDetail 对象,这是很常见的一种做法。

1.3. Google Cloud API

来源: https://cloud.google.com/apis/design/errors

{
    "error":{
        "code":400,
        "message":"API key not valid. Please pass a valid API key.",
        "status":"INVALID_ARGUMENT",
        "details":[
            {
                "@type":"type.googleapis.com/google.rpc.ErrorInfo",
                "reason":"API_KEY_INVALID",
                "domain":"googleapis.com",
                "metadata":{
                    "service":"translate.googleapis.com"
                }
            }
        ]
    }
}

Google API 设计指南建议的格式,是一个 Error.Status 对象。

1.4. Twitter/X API

来源: https://developer.twitter.com/en/support/x-api/error-troubleshooting

{
    "client_id":"101010101",
    "required_enrollment":"Standard Basic",
    "registration_url":"[https://developer.twitter.com/en/account](https://developer.twitter.com/en/account)",
    "title":"Client Forbidden",
    "detail":"This request must be made using an approved developer account that is enrolled in the requested endpoint. Learn more by visiting our documentation.",
    "reason":"client-not-enrolled",
    "type":"[https://api.twitter.com/2/problems/client-forbidden](https://api.twitter.com/2/problems/client-forbidden)"
}

Twitter 的错误格式,虽然没明说,其实就是下面要介绍的 RFC 7807/9457。

由此可见,各家都有自己定义的标准。但是其实标准化组织 IANA 已经定义了标准。

2. RFC 9457:Problem Details for HTTP APIs

2.1. 先说 RFC 7807

RFC 7807 是最初的版本。

RFC 7807 的目标是提供一种一致的方式来描述和传递 API 中的错误,以提高互操作性和开发人员的开发体验。它定义了一个标准的 JSON 格式,用于表示问题详情(Problem Details),包括错误代码、错误消息、错误描述等。

以下是 RFC 7807 中定义的 Problem Details 的基本结构:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
    "type":"[https://example.com/probs/out-of-credit](https://example.com/probs/out-of-credit)",
    "title":"You do not have enough credit.",
    "detail":"Your current balance is 30, but that costs 50.",
    "instance":"/account/12345/msgs/abc",
    "balance":30,
    "accounts":[
        "/account/12345",
        "/account/67890"
    ]
}

字段解释

  • type:字段表示问题类型,可以是一个 URL,用于唯一标识问题的类型。例如:https://example.com/validation-error.
  • title:人类可读的标识符,通常相同的类型字段应该有相同的标题字段旁边。一个例子是 Form validation failed
  • status:返回 HTTP 状态码,和实际状态码保持一致。
  • detail:关于具体问题的更多信息,如果可能,还有纠正它的步骤。例如,关于表单验证问题的信息用户名已被占用,请选择不同的用户名。
  • instance:此特定事件的标识符,它可能对客户端没有用处,但可用于问题排查。
  • 更多字段:可以添加任何字段来提供额外的信息,客户端可以忽略它们不支持的字段。

使用 RFC 7807 标准,API 可以以统一的方式返回错误和问题信息,使得客户端能够更好地理解和处理这些问题。该标准还提供了一些推荐的扩展字段,用于支持更多的自定义属性,以满足特定应用或领域的需求。

通过采用 RFC 7807 标准,API 开发人员可以提供一致和规范的错误处理机制,提高 API 的可用性、可维护性和互操作性。同时,客户端开发人员也可以更轻松地处理和解析 API 返回的问题信息。

建议还是去看看 RFC 原文: https://www.rfc-editor.org/rfc/rfc7807

2.2. RFC 9457

RFC 9457 是 RFC 7807 的更新版,是会替换 RFC 7807 的。

相对于 RFC 7807,它在继承所有字段的基础上,增加了 errors 错误信息数组,结构如下:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
Content-Language: en

{
    "type":"[https://example.net/validation-error](https://example.net/validation-error)",
    "title":"Your request is not valid.",
    "errors":[
        {
            "detail":"must be a positive integer",
            "pointer":"#/age"
        },
        {
            "detail":"must be 'green', 'red' or 'blue'",
            "pointer":"#/profile/color"
        }
    ]
}

这个 errors 字段主要用来描述验证错误,所以需要是一个数组。

errors 字段解释

  • detail:问题的描述。
  • pointer:使用 RFC 6901 定义的 JSON Pointer 指向请求的错误字段。

另外,因为 type 是一个 URL 字段,实际上这个字段可以涵盖多家厂商的错误类型,所以,IANA 建立了一个共享注册表,用来记录多家厂商的错误类型。但是目前为止,这个错误注册表还没有太多的信息。

错误注册表网址: https://www.iana.org/assignments/http-problem-types/http-problem-types.xhtml

更多信息请参考 RFC 原文: https://www.rfc-editor.org/rfc/rfc9457

3. 总结

这个标准还是挺话痨的。但既然有了标准,在设计新的 API 的时候,就尽量使用吧,在 IT 界,有时候的问题就是选择太多了,造成了混乱。与其手搓一个,还不如遵从一个标准。

想起了巴别塔的故事:

巴别塔的传说源自圣经《创世纪》第 11 章。根据传说,当时地球上的人类都使用同一种语言,并聚集在一起建造一座高耸入云的塔,被称为巴别塔(Tower of Babel)。人类的目的是建造一座塔,以达到天堂,并使他们的名字在整个地球上得到认可。然而,上帝看到人类的行为,并决定干涉他们的计划。为了阻止人类完成巴别塔,上帝使人类的语言变得混乱,使他们无法相互理解。人们开始说不同的语言,导致他们无法有效沟通和合作。由于语言的混乱,工程停顿,人们分散到世界各地,形成了不同的民族和语言群体。因此,巴别塔的传说被视为上帝对人类过于自负和傲慢的行为的惩罚,同时也解释了为什么世界上存在着不同的语言和文化。