錯誤響應
對於 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
方法返回 ProblemDetail
或 ErrorResponse
以渲染 RFC 9457 響應。處理過程如下
-
ProblemDetail
的status
屬性決定 HTTP 狀態。 -
ProblemDetail
的instance
屬性會在未設定時從當前 URL 路徑設定。 -
對於內容協商,在渲染
ProblemDetail
時,JacksonHttpMessageConverter
優先選擇“application/problem+json”而非“application/json”,如果找不到相容的媒體型別,也會回退到它。
要為 Spring MVC 異常和任何 ErrorResponseException
啟用 RFC 9457 響應,請擴充套件 ResponseEntityExceptionHandler
並將其宣告為 Spring 配置中的 @ControllerAdvice。該 handler 有一個 @ExceptionHandler
方法,用於處理任何 ErrorResponse
異常,包括所有內建的 Web 異常。您可以新增更多異常處理方法,並使用一個保護方法將任何異常對映到 ProblemDetail
。
您可以透過帶有 WebMvcConfigurer
的 MVC 配置註冊 ErrorResponse
攔截器。使用它來攔截任何 RFC 9457 響應並執行一些操作。
非標準欄位
您可以透過以下兩種方式之一使用非標準欄位擴充套件 RFC 9457 響應。
其一,插入到 ProblemDetail
的“properties” Map
中。使用 Jackson 庫時,Spring Framework 註冊了 ProblemDetailJacksonMixin
,它確保將此“properties” Map
解包並作為頂級 JSON 屬性渲染到響應中,同樣,反序列化期間任何未知屬性也會插入到此 Map
中。
您也可以擴充套件 ProblemDetail
以新增專用的非標準屬性。ProblemDetail
中的複製構造器允許子類輕鬆地從現有 ProblemDetail
建立新例項。這可以集中處理,例如,從像 ResponseEntityExceptionHandler
這樣的 @ControllerAdvice
中實現,它將異常的 ProblemDetail
重建為一個包含額外非標準欄位的子類例項。
定製和國際化 (i18n)
定製和國際化錯誤響應詳情是一個常見的需求。定製 Spring MVC 異常的問題詳情以避免暴露實現細節也是一個好的實踐。本節介紹對此的支援。
ErrorResponse
公開針對“type”、“title”和“detail”的訊息程式碼,以及針對“detail”欄位的訊息程式碼引數。ResponseEntityExceptionHandler
透過 MessageSource 解析這些程式碼,並相應地更新對應的 ProblemDetail
欄位。
訊息程式碼的預設策略如下
-
“type”:
problemDetail.type.[異常類的完全限定名]
-
“title”:
problemDetail.title.[異常類的完全限定名]
-
“detail”:
problemDetail.[異常類的完全限定名][字尾]
ErrorResponse
可能公開多個訊息程式碼,通常在預設訊息程式碼後新增字尾。下表列出了 Spring MVC 異常的訊息程式碼和引數
異常 | 訊息程式碼 | 訊息程式碼引數 |
---|---|---|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設)+ ".parseError" |
|
|
(預設) |
|
|
(預設)+ ".parseError" |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
|
(預設) |
|
與其他異常不同,MethodArgumentValidException 和 HandlerMethodValidationException 的訊息引數基於 MessageSourceResolvable 錯誤列表,這些錯誤也可以透過 MessageSource 資源包進行定製。有關更多詳情,請參閱定製驗證錯誤。 |