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