Spring Webflux的業務領域異常機制
最近我被分配了一個任務:在SpringBoot的Web應用中實現異常處理機制。就像幾乎所有SpringBoot專案一樣, 有許多不同的方法來實現它。以下是我的研究結果和最終解決方案。
需求
不同需求如下:
#1返回的錯誤訊息必須與框架提供的格式相容,特別是在JSON中,格式為:
{ <font>"timestamp"</font><font>: 1539797674906, </font><font>"path"</font><font>: </font><font>"/"</font><font>, </font><font>"status"</font><font>: 418, </font><font>"error"</font><font>: </font><font>"I'm a teapot"</font><font>, </font><font>"message"</font><font>: </font><font>"Teapot Mike!"</font><font> } </font>
出於多種原因,這種相容性很重要。
首先,API使用者始終使用相同的錯誤格式
其次,仍然可以使用JSR-303 / JSR-348 Bean驗證機制,我認為輸入驗證應該在域本身中進行,儘可能接近領域模型。然而,@NotNull等一些註釋欄位將讓我們拒絕傳入的請求因而無需進一步處理。如果發生驗證錯誤,則會在響應中新增一個附加欄位 - errors,這是對映到ofollow,noindex" target="_blank">BindingResult 物件的。
再者,現在有一種趨勢是將應用程式程式碼儘可能地與框架分開。雖然我知道這個目的,但我也意識到應用程式是沉浸在框架中 - 在這種情況下,我發現使用框架機制是合理的。
#2應用程式中丟擲的所有異常都應自動轉換為相應的HTTP狀態程式碼。
有人可能會想,我是想在應用程式中引入基於異常的通訊。當然不是。我希望所有的異常都可以在檢視層(@Controller)中解決。
#3所有異常應該從一個基類擴充套件(DomainException)
#4應該有一個集中的點,可以捕獲和處理所有異常。另外,如果可以將這樣的異常處理程式透明地注入到應用程式中,那將會很棒。
#5我想在錯誤響應中新增一個額外的欄位 - traceId。在基於微服務的應用程式中,它使除錯問題更少。
實現目標
要在基於Spring Webflux 的應用程式中處理異常,您可以:
- 使用本地@ExceptionHandler ,擴充套件ResponseStatusException 或使用@ResponseStatus 註釋的異常類。
- 提供帶註釋的自定義類@ControllerAdvice 。
- 提供擴充套件的自定義類DefaultErrorAttributes 。
該文批判了前面兩個點,理由非常饒人,這裡不做詳細闡述,文章最後推薦第三點:
第三點滿足所有要求:
滿足#1格式相容性 - 正如我之前所說,在Spring Framework中沒有代表錯誤響應的類,它只是一個Map。
對於#2和#3,我們有一個可擴充套件的DomainException - 一切都很好!
#4 DomainExceptionWrapper是一個可注入的單個元件,可以作為工件釋出到maven儲存庫,並作為依賴項新增到其他應用程式。當上下文啟動時,它將被自動檢測並作為bean注入。它也很容易測試。
#5由於所有(域,執行時,Spring)異常都在一個地方處理,而舊的異常被Map用作返回的物件,因此很容易從中新增或刪除欄位。