Skip to content
ADP
API Design PrincipleBETA

[ADP-401] HTTP 問題基礎

概述

錯誤回應是任何 API 的重要組成部分。顯然,HTTP 狀態碼對於錯誤(4xx,5xx)無法為 API 調用者提供足夠的資訊來準確理解發生了什麼。

過去我們可能會引入自定義錯誤代碼來描述標準 HTTP 狀態錯誤代碼以外的錯誤,但這並不清晰也不直觀。

目前 RFC 9457 提供了一種描述錯誤的標準方式,本 ADP 基於 RFC 9457 提供了一種設計錯誤回應的標準方法。

指導原則

  • 錯誤回應必須(MUST)與 HTTP Problem 兼容。

  • 錯誤回應必須(MUST)採用 JSON 格式。

  • 錯誤回應的 Content-Type 標頭必須(MUST)為 application/problem+json

  • 應(SHOULD)盡可能重用現有的問題類型:

    • [草案] 應(SHOULD)在內部問題類型註冊頁面註冊問題類型,參見 ADP-49
    • 問題類型命名必須(MUST)遵循 URI 慣例(kebab-case),參見 ADP-302
    • 問題類型必須(MUST)與產品無關且與業務模型無關。
  • 如果確實需要其他資訊,可以(MAY)添加額外屬性(property)來擴展問題 JSON

    http
    {
      "type": "https://example.net/validation-error",
      "title": "您的請求無效。",
      "extraInfo": "...."
    }
  • 問題類型無法描述清楚的,可以考慮設計額外類型,參見 ADP-403

錯誤回應結構

錯誤回應的範例:

http
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json

{
    type: '/problems/predefined-type',
    status: 500,
    title: '簡短的人類可讀錯誤描述',
    instance: '/items/12345',
    detail: '指引使用者如何修復問題'
}

錯誤回應的基本結構應如下:

屬性描述必需示例
type(string, uri-reference)必須是一個 URI(提示1)/problems/{problem-type}
title(string)問題類型的簡短、人類可讀摘要"Validation Error"
status(integer)原始伺服器為此問題實例生成的 HTTP 狀態碼400
detail(string)特定於此問題實例的人類可讀解釋(提示2)"提供的輸入無效,請提供正確格式。"
instance(string, uri-reference)標識問題特定實例的 URI 引用"/shop-items/123456"

提示1

理想情況下,這應該指向一個真實的網站,以提供更多關於該類型的資訊,正如 RFC 建議的那樣。

如果我們在引入問題類型時無法提供絕對 URI,使用相對 URI 是可以接受的。如:/problems/invalid-input

提示2 關於 ProblemJSON.detail

  • 如果其他屬性中已有足夠的資訊,detail 可以(MAY)為空。
  • detail 應為用戶提供如何修復問題的指示。也就是說,它應該(SHOULD)使用口語化的英語(或如果您的 API 支持 Accept-Language,則使用其他語言),如 RFC9457 中定義的那樣。
  • detailtitle 的區別: title 是一個更通用的問題簡短描述,而 detail 提供了修復問題的具體指示。
  • 如果您的 API 支持 Accept-Language,detail 可能是多語言的。無論您是否支持多語言,只要有 detail 屬性(property),就應該(SHOULD)指定 Content-Language

設計思路

許多網站使用自定義錯誤系統來描述 HTTP 狀態碼以外的自定義錯誤,例如額外的基於數字的代碼。然而,用戶仍然需要從互聯網查詢代碼的含義,因為不同應用程序之間沒有標準。

示例

讓我們以 Windows 錯誤代碼為例。參見 https://learn.microsoft.com/zh-tw/windows-hardware/drivers/debugger/bug-check-code-reference2

應該這樣做

json
{
  "type": "/problems/ipt-watchdog-timeout",
  "status": 500,
  "detail": "...."
}

不應該這樣做

json
{
  "status": "0x0001db"
}

參考

標準參考

設計參考