RFC:HTTP 线路错误

概述

本 RFC 提出了一种标准化方法,用于以一致且结构化的方式处理和表示 HTTP 线路错误。目标是提供清晰且详细的错误响应,以便客户端轻松理解和处理。

错误响应结构

每个错误响应都将遵循具有以下字段的标准化 JSON 结构:

  • id:错误实例的唯一标识符。
  • http_error_code:一个包含以下内容的对象:canonical_name:一个表示错误的规范名称的字符串。status:一个表示 HTTP 状态代码的整数。
  • 消息:错误的简短、可读的摘要。
  • 详细信息:针对此错误发生的特定且易于理解的解释。
  • 数据(可选):与错误相关的附加数据。
  • 验证(可选):验证错误数组,每个错误包含:字段:导致验证错误的字段名称。值:提供的无效值。原因:关于值无效的原因的人类可读的解释。
  • 例子

    {
        "id": "unique-error-id",
        "http_error_code": {
            "canonical_name": "ERROR_NAME",
            "status": 400
        },
        "message": "short summary of the error",
        "detail": "detailed explanation of the error",
        "data": {
            "additional": "context-specific data"
        },
        "validation": [
            {
                "field": "field_name",
                "value": "invalid_value",
                "reason": "explanation of why the value is invalid"
            }
        ]
    }

    规范错误名称

    定义了以下规范错误名称:

  • INVALID_ARGUMENT:表示客户端提供了无效的参数。
  • FAILED_PRECONDITION:表示由于系统未处于执行操作所需的状态而拒绝该操作。
  • OUT_OF_RANGE:表示尝试执行的操作超出了有效范围。
  • UNSUPPORTED_MEDIA_TYPE:表示请求实体具有服务器或资源不支持的媒体类型。
  • DEADLINE_EXCEEDED:表示操作完成前截止期限已到。
  • NOT_FOUND:表示找不到所请求的资源。
  • METHOD_NOT_ALLOWED:表示所使用的 HTTP 方法不受资源支持。
  • ALREADY_EXISTS:表示客户端尝试创建的资源已经存在。
  • ABORTED:表示操作已中止,通常是由于并发问题。
  • PERMISSION_DENIED:表示调用者没有权限执行指定的操作。
  • 未经认证:表示请求没有执行该操作的有效身份验证凭据。
  • RESOURCE_EXHAUSTED:表示某些资源已耗尽,可能是每个用户的配额,或者整个文件系统空间不足。
  • TOO_LARGE:表示请求实体大于服务器定义的限制。
  • UNIMPLEMENTED:表示该操作未实现或者在此服务中不受支持/启用。
  • UNAVAILABLE:表示该服务当前不可用。
  • INTERNAL:表示服务器内部错误。
  • DATA_LOSS:表示不可恢复的数据丢失或损坏。
  • UNKNOWN:表示未知错误。
  • PAYMENT_REQUIRED:表示访问资源需要付款。
  • NOT_ACCEPTABLE:表示资源无法生成根据请求中发送的 Accept 标头可接受的内容。
  • PROXY_AUTH_REQUIRED:表示客户端必须首先向代理进行自身身份验证。
  • REQUEST_TIMEOUT:表明服务器等待请求超时。
  • GONE:表示请求的资源不再可用,并且不会再次可用。
  • LENGTH_REQUIRED:表示请求未指定其内容的长度,而这是所请求的资源所必需的。
  • PRECONDITION_FAILED:表示服务器不满足请求者在请求中提出的先决条件之一。
  • REQUEST_URI_TOO_LONG:表示提供的 URI 太长,服务器无法处理。
  • REQUESTED_RANGE_NOT_SATISFIABLE:表示服务器无法提供所请求的文件部分。
  • EXPECTATION_FAILED:表示服务器无法满足 Expect 请求标头字段的要求。
  • IM_A_TEAPOT:表示服务器拒绝煮咖啡,因为它永远是一个茶壶。
  • MISDIRECTED_REQUEST:表示请求指向无法产生响应的服务器。
  • UNPROCESSABLE_ENTITY:表示服务器理解请求实体的内容类型,但无法处理其中包含的指令。
  • LOCKED:表示正在访问的资源已被锁定。
  • FAILED_DEPENDENCY:表示由于前一个请求失败而导致该请求失败。
  • TOO_EARLY:表示服务器不愿意冒险处理可能被重放的请求。
  • UPGRADE_REQUIRED:表示客户端应该切换到不同的协议。
  • PRECONDITION_REQUIRED:表示源服务器要求请求是有条件的。
  • REQUEST_HEADER_FIELDS_TOO_LARGE:表示服务器不愿意处理该请求,因为其标头字段太大。
  • UNAVAILABLE_FOR_LEGAL_REASONS:表示资源由于法律原因不可用。
  • HTTP_VERSION_NOT_SUPPORTED:表示服务器不支持请求中使用的HTTP协议版本。
  • VARIANT_ALSO_NEGOTIATES:表示服务器存在内部配置错误。
  • INSUFFICIENT_STORAGE:表示服务器无法存储完成请求所需的表示。
  • LOOP_DETECTED:表示服务器在处理请求时检测到无限循环。
  • NOT_EXTENDED:表示服务器需要进一步扩展请求才能满足该请求。
  • NETWORK_AUTHENTICATION_REQUIRED:表示客户端需要进行身份验证才能获得网络访问权限。
  • PAGE_EXPIRED:表示该页面已过期。
  • BLOCKED_BY_WINDOWS_PARENTAL_CONTROLS:表示该请求被 Windows 家长控制阻止。
  • INVALID_TOKEN:表示提供的令牌无效。
  • TOKEN_REQUIRED:表示访问资源需要令牌。
  • BANDWIDTH_LIMIT_EXCEEDED:表示已超出带宽限制。
  • INVALID_SSL_CERTIFICATE:表示 SSL 证书无效。
  • SITE_OVERLOADED:表示站点已超载。
  • SITE_FROZEN:表示站点已被冻结。
  • NETWORK_READ_TIMEOUT:表示发生网络读取超时错误。
  • 错误处理

    无效参数

    当客户端提供无效参数时,服务器应该响应“INVALID_ARGUMENT”错误。

    例子

    {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "http_error_code": {
            "canonical_name": "INVALID_ARGUMENT",
            "status": 400
        },
        "message": "invalid account number provided",
        "detail": "the account number '123456789' does not exist in our records"
    }

    不满足先决条件

    当操作由于先决条件不满足而被拒绝时,服务器应该响应“FAILED_PRECONDITION”错误。

    例子

    {
        "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
        "http_error_code": {
            "canonical_name": "FAILED_PRECONDITION",
            "status": 400
        },
        "message": "insufficient funds",
        "detail": "the account '987654321' has insufficient funds for the transaction",
        "data": {
            "current_balance": 50.00,
            "required_balance": 100.00
        }
    }

    未认证

    当请求缺少有效的身份验证凭证时,服务器应该响应“UNAUTHENTICATED”错误。

    例子

    {
        "id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
        "http_error_code": {
            "canonical_name": "UNAUTHENTICATED",
            "status": 401
        },
        "message": "unauthorized access",
        "detail": "the provided credentials are invalid"
    }

    未经授权的访问

    由于 JWK 无效。

    {
        "id": "b445b036-fd2e-4583-b4cc-61c2b8fb0b73",
        "http_error_code": {
            "canonical_name": "UNAUTHENTICATED",
            "status": 401
        },
        "message": "auth: verify: jwt: unknown kid"
    }

    没有权限

    当调用者没有权限执行指定的操作时,服务器应该响应“PERMISSION_DENIED”错误。

    例子

    {
        "id": "d4e5f6a7-b8c9-0123-def4-567890123456",
        "http_error_code": {
            "canonical_name": "PERMISSION_DENIED",
            "status": 403
        },
        "message": "account locked",
        "detail": "the account '123456789' is locked due to multiple failed login attempts",
        "data": {
            "lock_duration": "24 hours"
        }
    }

    未找到

    当找不到请求的资源时,服务器应该响应“NOT_FOUND”错误。

    例子

    {
        "id": "e5f6a7b8-c9d0-1234-ef56-789012345678",
        "http_error_code": {
            "canonical_name": "NOT_FOUND",
            "status": 404
        },
        "message": "transaction not found",
        "detail": "the transaction with id 'tx1234567890' was not found"
    }

    验证错误

    当请求包含无效字段时,服务器应该响应“INVALID_ARGUMENT”错误并包含验证详细信息。

    例子

    {
        "id": "c30adf71-25c0-4a2b-a1f2-c3ee17efcd17",
        "http_error_code": {
            "canonical_name": "INVALID_ARGUMENT",
            "status": 400
        },
        "message": "validation failure",
        "detail": "fields were invalid",
        "validation": [
            {
                "field": "name",
                "value": "jo",
                "reason": "name must be at least 3 characters long"
            },
            {
                "field": "email",
                "value": "invalid@comcom",
                "reason": "email must be a valid email address"
            }
        ]
    }

    内部服务器错误

    当处理请求时发生意外错误时,服务器应该以“内部”错误进行响应。

    {
        "id": "f6a7b8c9-d0e1-2345-f678-901234567890",
        "http_error_code": {
            "canonical_name": "INTERNAL",
            "status": 500
        },
        "message": "server error",
        "detail": "an unexpected error occurred while processing the request"
    }

    嵌套数据的复杂误差

    当错误涉及多个嵌套错误时,服务器应该为错误消息的每个部分提供详细的上下文。

    例子

    {
        "id": "9f8b7c6d-4e5f-4a2b-8c3d-1e2f3a4b5c6d",
        "http_error_code": {
            "canonical_name": "FAILED_PRECONDITION",
            "status": 400
        },
        "message": "transaction failed: insufficient funds: daily withdrawal limit exceeded",
        "data": [
            {
                "message": "transaction failed",
                "data": {
                    "transaction_id": "tx1234567890",
                    "amount": 150.00,
                    "currency": "USD"
                }
            },
            {
                "message": "insufficient funds",
                "data": {
                    "account_id": "acc987654321",
                    "current_balance": 50.00,
                    "required_balance": 150.00
                }
            },
            {
                "message": "daily withdrawal limit exceeded",
                "data": {
                    "account_id": "acc987654321",
                    "daily_limit": 1000.00,
                    "amount_attempted": 1500.00
                }
            }
        ]
    }

    在此示例中,错误消息由三部分组成:

  • 交易失败
  • 资金不足
  • 每日提现限额已超出
  • 错误消息的每个部分都有自己的数据部分,为错误的每个部分提供详细的上下文。这种结构使客户端能够了解与错误消息的每个部分相关的具体上下文和数据,从而更轻松地调试和解决问题。

    问题详细信息

    问题详细信息 RFC 是一种用于表示 HTTP API 中的错误的标准化格式。它定义了一种结构化的方式,以机器可读的格式提供有关错误的详细信息,使客户端更容易理解和有效地处理错误。

    例子

    {
        "status": 400,
        "title": "Insufficient Funds",
        "detail": "The account '987654321' has insufficient funds for the transaction.",
        "type": "https://example.com/probs/insufficient-funds",
        "instance": "/accounts/12345/transactions/67890",
        "extra_custom_key": "current_balance",
        "extra_custom_value": 50.00,
        "extra_custom_key2": "required_balance",
        "extra_custom_value2": 100.00
    }

    HTTP 线路错误和问题详情之间的差异

    虽然 HTTP 线路错误和问题详细信息都提供了一种结构化的方式来表示 HTTP API 中的错误,但仍存在一些主要区别:

  • 灵活性:HTTP Wire Errors 提供更灵活的结构,可以包含其他字段,例如 id、http_error_code、消息、数据和验证。这样可以提供更详细且特定于上下文的错误信息。
  • 规范错误名称:HTTP Wire 错误定义了一组规范的错误名称,这些名称标准化了常见的错误场景,使得在应用程序的不同部分对错误进行分类和一致处理变得更加容易。
  • 嵌套数据:HTTP Wire Errors 支持嵌套数据结构,允许为复杂错误消息的每个部分提供详细的上下文。这对于涉及多个相关问题的错误特别有用。
  • 验证错误:HTTP Wire 错误包含一个专用的验证字段,用于提供有关验证错误的详细信息,包括具体字段和验证失败的原因。
  • 问题细节缺失了什么

    问题详细信息 (RFC 7807) 提供了表示错误的标准化格式,但它们缺少 HTTP Wire Errors 解决的一些功能:

  • 规范错误名称:问题详细信息没有定义一组规范的错误名称,这可能导致错误分类不一致。
  • 嵌套数据:问题详细信息本身不支持嵌套数据结构,因此更难为复杂错误提供详细的上下文。
  • 验证错误:问题详细信息没有用于验证错误的专门字段,这使得提供有关验证问题的详细信息变得更加困难。
  • HTTP 线路错误如何提供解决方案

    HTTP Wire Errors 通过以下方式解决这些限制:

  • 定义一组规范的错误名称,以实现一致的错误分类。
  • 支持嵌套数据结构,为复杂错误提供详细的上下文。
  • 包括一个专用的验证字段,用于详细的验证错误信息。
  • 作者

    Gerasimos Maropoulos 是 Iris Web 框架的作者,该框架是 Go 编程语言的一款高效且功能丰富的 Web 框架。他在编程社区中因其对 Web 开发的贡献和对 Go 语言的专业知识而闻名。Gerasimos 撰写了大量在线文章和教程,帮助开发人员了解和利用 Go 的强大功能来构建可扩展且高性能的 Web 应用程序。他在 Iris 上的工作使其成为 Go 生态系统中最受欢迎的 Web 框架之一,以其简单、快速和广泛的功能集而闻名。

    Gerasimos 编写此 RFC 是为了满足对处理和表示 HTTP 线路错误的标准化方法的需求。通过为错误响应提供清晰一致的结构,他的目标是让开发人员更容易调试和了解其应用程序中的错误上下文。此 RFC 是他不断努力改善开发人员体验并确保使用 Iris 构建的应用程序稳健且可维护的一部分。

    结论

    此 RFC 定义了处理和表示 HTTP 线路错误的标准化方法。通过遵循此结构,开发人员可以确保一致且清晰的错误响应,从而使客户端更容易理解和有效处理错误。