錯誤回應

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

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

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

  • ErrorResponse — 暴露 HTTP 錯誤回應詳情的契約,包括 HTTP 狀態、回應標頭和 RFC 9457 格式的 body;這允許例外狀況封裝並暴露它們如何對應到 HTTP 回應的詳細資訊。 所有 Spring WebFlux 例外狀況都實作了此契約。

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

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

呈現

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

  • ProblemDetailstatus 屬性決定 HTTP 狀態。

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

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

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

您可以使用 WebFluxConfigurer 透過 WebFlux 組態 註冊 ErrorResponse 攔截器。 使用它來攔截任何 RFC 9457 回應並採取一些動作。

非標準欄位

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

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

您也可以擴充 ProblemDetail 以新增專用的非標準屬性。 ProblemDetail 中的複製建構子允許子類別輕鬆地從現有的 ProblemDetail 建立它。 這可以集中完成,例如,從 @ControllerAdvice(例如 ResponseEntityExceptionHandler)完成,該 @ControllerAdvice 會將例外狀況的 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 方法將錯誤回應 body 解碼為任何目標類型,例如 ProblemDetailProblemDetail 的子類別。