錯誤響應

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

以下是此支援的主要抽象

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

  • ErrorResponse — 暴露 HTTP 錯誤響應詳情的契約,包括 HTTP 狀態、響應頭和 RFC 9457 格式的響應體;這允許異常封裝並暴露它們如何對映到 HTTP 響應的詳細資訊。所有 Spring WebFlux 異常都實現了此契約。

  • ErrorResponseException — 基本的 ErrorResponse 實現,其他類可以將其用作方便的基類。

  • ResponseEntityExceptionHandler@ControllerAdvice 的便捷基類,用於處理所有 Spring WebFlux 異常和任何 ErrorResponseException,並渲染帶有響應體的錯誤響應。

渲染

你可以從任何 @ExceptionHandler 或 `@RequestMapping` 方法返回 ProblemDetailErrorResponse 來渲染 RFC 9457 響應。其處理方式如下

  • ProblemDetailstatus 屬性決定 HTTP 狀態。

  • 如果 ProblemDetailinstance 屬性尚未設定,則從當前 URL 路徑設定該屬性。

  • 對於內容協商,當渲染 ProblemDetail 時,Jackson HttpMessageConverter 優先選擇 "application/problem+json" 而非 "application/json",如果在沒有找到相容的媒體型別時也會回退到它。

要為 Spring WebFlux 異常和任何 ErrorResponseException 啟用 RFC 9457 響應,請擴充套件 ResponseEntityExceptionHandler 並在 Spring 配置中將其宣告為 @ControllerAdvice。該處理器有一個 `@ExceptionHandler` 方法,用於處理任何 ErrorResponse 異常,包括所有內建的 Web 異常。你可以新增更多的異常處理方法,並使用一個 protected 方法將任何異常對映到 ProblemDetail

你可以透過 WebFlux 配置 使用 WebFluxConfigurer 註冊 ErrorResponse 攔截器。使用它來攔截任何 RFC 9457 響應並執行某些操作。

非標準欄位

你可以透過以下兩種方式之一,使用非標準欄位擴充套件 RFC 9457 響應。

第一種,將欄位插入到 ProblemDetail 的 "properties" Map 中。當使用 Jackson 庫時,Spring Framework 會註冊 ProblemDetailJacksonMixin,該 Mixin 確保將這個 "properties" Map 展開並渲染為響應中的頂級 JSON 屬性,同樣地,在反序列化過程中,任何未知屬性都會被插入到這個 Map 中。

你也可以擴充套件 ProblemDetail 來新增專門的非標準屬性。ProblemDetail 中的複製建構函式允許子類輕鬆地從現有 ProblemDetail 建立自身。這可以集中處理,例如,在一個 `@ControllerAdvice` (如 ResponseEntityExceptionHandler) 中,將異常的 ProblemDetail 重新建立為一個包含附加非標準欄位的子類。

定製和國際化 (i18n)

定製錯誤響應詳情並進行國際化是一個常見的需求。定製 Spring WebFlux 異常的問題詳情以避免暴露實現細節也是一個好的實踐。本節介紹對此的支援。

一個 ErrorResponse 暴露了 "type"、"title" 和 "detail" 的訊息程式碼,以及 "detail" 欄位的訊息程式碼引數。ResponseEntityExceptionHandler 透過 MessageSource 解析這些程式碼,並相應地更新對應的 ProblemDetail 欄位。

訊息程式碼的預設策略遵循以下模式

problemDetail.[type|title|detail].[異常的完全限定類名]

一個 ErrorResponse 可能會暴露多個訊息程式碼,通常是在預設訊息程式碼後新增一個字尾。下表列出了 Spring WebFlux 異常的訊息程式碼和引數

異常 訊息程式碼 訊息程式碼引數

HandlerMethodValidationException

(預設)

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

MethodNotAllowedException

(預設)

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

MissingRequestValueException

(預設)

{0} 值的標籤(例如,“請求頭”,“cookie 值”,...),{1} 值名稱

NotAcceptableStatusException

(預設)

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

NotAcceptableStatusException

(預設) + ".parseError"

ServerErrorException

(預設)

{0} 提供給類建構函式的失敗原因

UnsupportedMediaTypeStatusException

(預設)

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

UnsupportedMediaTypeStatusException

(預設) + ".parseError"

UnsatisfiedRequestParameterException

(預設)

{0} 引數條件列表

WebExchangeBindException

(預設)

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

與其他異常不同,WebExchangeBindExceptionHandlerMethodValidationException 的訊息引數基於 MessageSourceResolvable 錯誤列表,這些錯誤也可以透過 MessageSource 資源包進行定製。詳情請參閱 定製驗證錯誤

客戶端處理

客戶端應用在使用 WebClient 時可以捕獲 WebClientResponseException,或在使用 RestTemplate 時捕獲 RestClientResponseException,並使用它們的 getResponseBodyAs 方法將錯誤響應體解碼為任何目標型別,例如 ProblemDetailProblemDetail 的子類。