Spring?WebFlux怎么進行異常處理源碼解析
1 概覽
在本教程中,我們將通過一個實際示例了解Spring WebFlux項目中處理錯誤的各種策略。
我們還將指出使用一種策略比另一種策略更有利的地方,并在最后提供完整源代碼的鏈接。
2 開始示例代碼
maven 設置和之前介紹 Spring WebFlux 的文章一樣,
對于我們的示例,我們將使用一個 RESTful 端點,它將用戶名作為查詢參數(shù)并返回“Hello username”作為結果。首先,讓我們創(chuàng)建一個路由函數(shù),這個路由函數(shù)將 “/hello” 請求路由到處理程序中名為 handleRequest 的方法,代碼如下:
@Bean public RouterFunction<ServerResponse> routeRequest(Handler handler) { return RouterFunctions.route(RequestPredicates.GET("/hello") .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), handler::handleRequest); }
然后,我們定義個 handleRequest() 方法,這個方法調用 sayHello() 方法,并找到一個在 ServerResponse 中包含或返回其(sayHello方法的返回)結果的方法。
public Mono<ServerResponse> handleRequest(ServerRequest request) { return //... sayHello(request) //... }
最后,實現(xiàn) sayHello 方法,實現(xiàn)很簡單,直接拼接 hello 和參數(shù) username 即可。
private Mono<String> sayHello(ServerRequest request) { try { // 應該是 username return Mono.just("Hello, " + request.queryParam("username").get()); } catch (Exception e) { return Mono.error(e); } }
因此,只要我們的請求中帶了 username 參數(shù),我們的請求就能正常返回。舉個例子:我們請求“/hello?username=Tonni”,類似請求,我們總是能正常返回。
然而,如果我們的請求不帶 username 參數(shù),我們的請求就會拋出異常了。下面,我們來看看 Spring WebFlux 在哪里以及怎么重組代碼來處理我們的異常。
3 方法級別處理異常
Mono 和 Flux API 中內置了兩個關鍵運算符來處理方法級別的錯誤。我們簡要探討一下它們及其用法。
3.1 onErrorReturn 處理異常
當我們碰到異常的時候,我們可以用 onErrorReturn 來直接返回靜態(tài)結果:
public Mono<ServerResponse> handleRequest(ServerRequest request) { return sayHello(request) .onErrorReturn("Hello Stranger") .flatMap(s -> ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .bodyValue(s)); }
這里,每當有問題的連接函數(shù)拋出異常的時候,我們直接返回一個靜態(tài)結果:“Hello Stranger”。
3.2 onErrorResume 處理異常
有三種使用 onErrorResume 處理異常的方式:
- 計算動態(tài)回調值
- 通過回調函數(shù)執(zhí)行其他分支
- 捕獲、包裝并重新拋出錯誤,例如,作為自定義業(yè)務異常
讓我們看看怎么計算值:
public Mono<ServerResponse> handleRequest(ServerRequest request) { return sayHello(request) .flatMap(s -> ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .bodyValue(s)) .onErrorResume(e -> Mono.just("Error " + e.getMessage()) .flatMap(s -> ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .bodyValue(s))); }
這里,每當 sayHello 拋出異常的時候,我們返回一個 “Error + 異常信息(e.getMessage())”。
接下來,我們看看當異常發(fā)生調用回調函數(shù):
public Mono<ServerResponse> handleRequest(ServerRequest request) { return sayHello(request) .flatMap(s -> ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .bodyValue(s)) .onErrorResume(e -> sayHelloFallback() .flatMap(s -> ServerResponse.ok() .contentType(MediaType.TEXT_PLAIN) .bodyValue(s))); }
這里,每當 sayHello 拋出異常的時候,我們執(zhí)行一個其他函數(shù) sayHelloFallback 。
最后,使用 onErrorResume 來捕獲、包裝并重新拋出錯誤,舉例如:NameRequiredException
public Mono<ServerResponse> handleRequest(ServerRequest request) { return ServerResponse.ok() .body(sayHello(request) .onErrorResume(e -> Mono.error(new NameRequiredException( HttpStatus.BAD_REQUEST, "username is required", e))), String.class); }
這里,當 sayHello 拋出異常的時候,我們拋出一個定制異常 NameRequiredException,message是 “username is required”。
全局處理異常
目前為止,我們提供的所有示例都在方法級別上處理了錯誤處理。但是我們可以選擇在全局層面處理異常。為此,我們只需要兩步:
- 自定義一個全局錯誤響應屬性
- 實現(xiàn)全局錯誤處理 handler
這樣我們程序拋出的異常將會自動轉換成 HTTP 狀態(tài)和 JSON 錯誤體。我們只需要繼承 DefaultErrorAttributes 類然后重寫 getErrorAttributes 方法就可以自定義這些。
public class GlobalErrorAttributes extends DefaultErrorAttributes{ @Override public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) { Map<String, Object> map = super.getErrorAttributes( request, options); map.put("status", HttpStatus.BAD_REQUEST); map.put("message", "username is required"); return map; } }
這里,當異常拋出是,我們想要返回 BAD_REQUEST 狀態(tài)碼和“username is required”錯誤信息作為錯誤屬性的一部分。
然后,我們來實現(xiàn)全局錯誤處理 handler。
為此,Spring 提供了一個方便的 AbstractErrorWebExceptionHandler 類,供我們在處理全局錯誤時進行擴展和實現(xiàn):
@Component @Order(-2) public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { // constructors @Override protected RouterFunction<ServerResponse> getRoutingFunction( ErrorAttributes errorAttributes) { return RouterFunctions.route( RequestPredicates.all(), this::renderErrorResponse); } private Mono<ServerResponse> renderErrorResponse( ServerRequest request) { Map<String, Object> errorPropertiesMap = getErrorAttributes(request, ErrorAttributeOptions.defaults()); return ServerResponse.status(HttpStatus.BAD_REQUEST) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(errorPropertiesMap)); } }
在這個例子中,我們設置 handler 的 order 為 -2。這是為了給它一個比默認 handler,也就是 DefaultErrorWebExceptionHandler 一個更高的優(yōu)先級,它設置的 order 為 -1。
errorAttributes 對象將是我們在 Web 異常處理程序的構造函數(shù)中傳遞的對象的精確副本。理想情況下,這應該是我們自定義的錯誤屬性類。
然后我們明確生命了,我們希望將所有的異常處理路由到 renderErrorResponse() 中。
最后,我們獲取了錯誤屬性并插入到服務端響應體中。
然后這會生成一個 JSON 響應,其中包含了錯誤的詳細信息,HTTP 狀態(tài)、機器端的異常信息等。對于瀏覽器端,它有一個 “white-label”錯誤處理程序,可以以 HTML 形式呈現(xiàn)相同的數(shù)據(jù),當然這個頁面可以定制。
總結
在本文中,我們研究了在 Spring WebFlux 項目中處理異常的集中策略,并指出使用一個策略優(yōu)于其他策略的地方。
翻譯自原文:https://www.baeldung.com/spri...
以上就是Spring WebFlux怎么進行異常處理源碼解析的詳細內容,更多關于Spring WebFlux異常處理的資料請關注腳本之家其它相關文章!
相關文章
Java實現(xiàn)獲取cpu、內存、硬盤、網絡等信息的方法示例
這篇文章主要介紹了Java實現(xiàn)獲取cpu、內存、硬盤、網絡等信息的方法,涉及java使用第三方jar包針對本機硬件的cpu、內存、硬盤、網絡信息等的讀取相關操作技巧,需要的朋友可以參考下2018-06-06Mybatis返回單個實體或者返回List的實現(xiàn)
這篇文章主要介紹了Mybatis返回單個實體或者返回List的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07MybatisPlus多數(shù)據(jù)源及事務解決思路
這篇文章主要介紹了MybatisPlus多數(shù)據(jù)源及事務解決思路,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01IDEA中創(chuàng)建maven項目webapp目錄無法識別即未被標識的解決辦法
在學習SpringMVC課程中,基于IDEA新建maven項目模塊后,webapp目錄未被標識,即沒有小藍點的圖標顯示,所以本文給大家介紹了IDEA中創(chuàng)建maven項目webapp目錄無法識別即未被標識的解決辦法,需要的朋友可以參考下2024-03-03自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問題
這篇文章主要介紹了自主配置數(shù)據(jù)源,mybatis/plus不打印sql日志問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12