錯誤回應

REST 服務的常見需求是在錯誤回應的主體中包含詳細資訊。Spring Framework 支援 "HTTP API 的問題詳情" 規範,RFC 9457。

以下是此支援的主要抽象概念

  • ProblemDetail — RFC 9457 問題詳情的表示;一個簡單的容器,用於規範中定義的標準欄位和非標準欄位。

  • ErrorResponse — 用於公開 HTTP 錯誤回應詳細資訊的契約,包括 HTTP 狀態、回應標頭和 RFC 9457 格式的主體;這允許例外狀況封裝並公開它們如何映射到 HTTP 回應的詳細資訊。所有 Spring MVC 例外狀況都實作了此契約。

  • ErrorResponseException — 其他人可以用作方便的基底類別的基本 ErrorResponse 實作。

  • ResponseEntityExceptionHandler — 用於 @ControllerAdvice 的方便的基底類別,它處理所有 Spring MVC 例外狀況和任何 ErrorResponseException,並呈現帶有主體的錯誤回應。

呈現

您可以從任何 @ExceptionHandler 或任何 @RequestMapping 方法傳回 ProblemDetailErrorResponse 以呈現 RFC 9457 回應。處理方式如下

  • ProblemDetailstatus 屬性決定 HTTP 狀態。

  • 如果尚未設定,ProblemDetailinstance 屬性會從目前的 URL 路徑設定。

  • 對於內容協商,Jackson HttpMessageConverter 在呈現 ProblemDetail 時,偏好 "application/problem+json" 而非 "application/json",如果找不到相容的媒體類型,也會回退到 "application/json"。

若要為 Spring WebFlux 例外狀況和任何 ErrorResponseException 啟用 RFC 9457 回應,請擴充 ResponseEntityExceptionHandler 並在 Spring 配置中將其宣告為 @ControllerAdvice。處理器具有一個 @ExceptionHandler 方法,用於處理任何 ErrorResponse 例外狀況,其中包括所有內建的 Web 例外狀況。您可以新增更多例外狀況處理方法,並使用受保護的方法將任何例外狀況映射到 ProblemDetail

您可以透過 MVC 配置和 WebMvcConfigurer 註冊 ErrorResponse 攔截器。使用它來攔截任何 RFC 9457 回應並採取一些動作。

非標準欄位

您可以透過兩種方式之一使用非標準欄位擴充 RFC 9457 回應。

第一種方式,插入到 ProblemDetail 的 "properties" Map 中。當使用 Jackson 函式庫時,Spring Framework 會註冊 ProblemDetailJacksonMixin,以確保此 "properties" Map 在回應中被解包並呈現為頂層 JSON 屬性,同樣地,反序列化期間的任何未知屬性都會插入到此 Map 中。

您也可以擴充 ProblemDetail 以新增專用的非標準屬性。ProblemDetail 中的複製建構子允許子類別輕鬆地從現有的 ProblemDetail 建立它。這可以集中完成,例如,從 @ControllerAdvice(例如 ResponseEntityExceptionHandler)完成,它將例外狀況的 ProblemDetail 重新建立為具有其他非標準欄位的子類別。

自訂與國際化 (i18n)

自訂和國際化錯誤回應詳細資訊是一個常見需求。自訂 Spring MVC 例外狀況的問題詳情以避免洩漏實作細節也是一種良好的做法。本節描述對此的支援。

ErrorResponse 公開 "type"、"title" 和 "detail" 的訊息代碼,以及 "detail" 欄位的訊息代碼引數。ResponseEntityExceptionHandler 透過 MessageSource 解析這些代碼,並相應地更新對應的 ProblemDetail 欄位。

訊息代碼的預設策略如下

  • "type":problemDetail.type.[完整限定例外狀況類別名稱]

  • "title":problemDetail.title.[完整限定例外狀況類別名稱]

  • "detail":problemDetail.[完整限定例外狀況類別名稱][suffix]

ErrorResponse 可能會公開多個訊息代碼,通常會將後綴新增至預設訊息代碼。下表列出了訊息代碼和 Spring MVC 例外狀況的引數

例外狀況 訊息代碼 訊息代碼引數

AsyncRequestTimeoutException

(預設)

ConversionNotSupportedException

(預設)

{0} 屬性名稱,{1} 屬性值

HandlerMethodValidationException

(預設)

{0} 列出所有驗證錯誤。每個錯誤的訊息代碼和引數也會透過 MessageSource 解析。

HttpMediaTypeNotAcceptableException

(預設)

{0} 支援的媒體類型列表

HttpMediaTypeNotAcceptableException

(預設) + ".parseError"

HttpMediaTypeNotSupportedException

(預設)

{0} 不支援的媒體類型,{1} 支援的媒體類型列表

HttpMediaTypeNotSupportedException

(預設) + ".parseError"

HttpMessageNotReadableException

(預設)

HttpMessageNotWritableException

(預設)

HttpRequestMethodNotSupportedException

(預設)

{0} 目前的 HTTP 方法,{1} 支援的 HTTP 方法列表

MethodArgumentNotValidException

(預設)

{0} 全域錯誤列表,{1} 欄位錯誤列表。每個錯誤的訊息代碼和引數也會透過 MessageSource 解析。

MissingRequestHeaderException

(預設)

{0} 標頭名稱

MissingServletRequestParameterException

(預設)

{0} 請求參數名稱

MissingMatrixVariableException

(預設)

{0} 矩陣變數名稱

MissingPathVariableException

(預設)

{0} 路徑變數名稱

MissingRequestCookieException

(預設)

{0} Cookie 名稱

MissingServletRequestPartException

(預設)

{0} 部件名稱

NoHandlerFoundException

(預設)

NoResourceFoundException

(預設)

TypeMismatchException

(預設)

{0} 屬性名稱,{1} 屬性值

UnsatisfiedServletRequestParameterException

(預設)

{0} 參數條件列表

與其他例外狀況不同,MethodArgumentValidExceptionHandlerMethodValidationException 的訊息引數基於 MessageSourceResolvable 錯誤列表,這些錯誤也可以透過 MessageSource 資源套件進行自訂。請參閱「自訂驗證錯誤」以取得更多詳細資訊。

客戶端處理

當使用 WebClient 時,客戶端應用程式可以捕獲 WebClientResponseException,當使用 RestTemplate 時,可以捕獲 RestClientResponseException,並使用其 getResponseBodyAs 方法將錯誤回應主體解碼為任何目標類型,例如 ProblemDetailProblemDetail 的子類別。