【翻譯】在Spring WebFlux中處理錯誤
1. 概覽
在本教程中,我們通過一個實際的例子來看一下可用於處理Spring WebFlux專案中的錯誤的各種策略。
我們還將指出在哪種情況下使用一種策略會比另外一種好,在本文最後將提供所有原始碼的下載地址。
2. 配置例項
上一篇文章 previous article 中已經提到了maven的配置, 並對 Spring Webflux做了簡單的介紹。
在這個例子中,我們為一個 RESTful 端點加上一個名為 username 的查詢引數,並以“Hello username”作為結果返回。
First, let’s create a router function that routes the /hello request to a method named handleRequest in the passed-in handler:
首先,讓我們建立一個路由器函式,將/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主體中包含/返回其結果的方法:
public Mono<ServerResponse> handleRequest(ServerRequest request) {
return
//...
sayHello(request)
//...
}
最後,sayHello()是一個簡單的實用工具方法,它將“Hello”和 username 連線起來返回。
private Mono<String> sayHello(ServerRequest request) {
//...
return Mono.just("Hello, " + request.queryParam("name").get());
//...
}
只要用 username 作為我們請求的一部分存在,例如使用“/hello?username=Tonni”訪問,我們的端點就可以正確執行。
然而,如果我們呼叫"/hello"的時候沒有使用 username 這個引數,它會丟擲一個異常。
下面,我們將看看我們在何處如何重新組織我們的程式碼才能在WebFlux中處理此異常。
3. 在函式級別處理錯誤
Mono和Flux API內建了兩個關鍵操作符,用於處理功能級別的錯誤。
讓我們簡要地探討它們及其用法。
3.1. 使用 onErrorReturn
當出現錯誤時,我們可以使用 onErrorReturn()來返回一個靜態的預設值。
public Mono<ServerResponse> handleRequest(ServerRequest request) {
return sayHello(request)
.onErrorReturn("Hello Stranger")
.flatMap(s -> ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(s));
}
當 sayHello()丟擲異常時,函式就會預設返回"Hello Stranger"。
3.2. 使用onErrorResume
使用onErrorResume處理錯誤有三種方式:
- 計算動態返回值
- 使用fallback方法 跳轉到備份路徑
- 捕獲,包裝和重新丟擲錯誤,例如 作為自定義業務異常
讓我們看看怎麼楊計算一個值:
public Mono<ServerResponse> handleRequest(ServerRequest request) {
return sayHello(request)
.flatMap(s -> ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(s))
.onErrorResume(e -> Mono.just("Error " + e.getMessage())
.flatMap(s -> ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(s)));
}
在這裡,每當sayHello()丟擲異常時,我們將返回一個字串,該字串由附加到字串“Error”的動態獲取的錯誤訊息組成。
接下來,當錯誤發生時我們呼叫 fallback 方法:
public Mono<ServerResponse> handleRequest(ServerRequest request) {
return sayHello(request)
.flatMap(s -> ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(s))
.onErrorResume(e -> sayHelloFallback()
.flatMap(s ->; ServerResponse.ok()
.contentType(MediaType.TEXT_PLAIN)
.syncBody(s)));
}
在這裡,只要sayHello()丟擲異常,我們就會呼叫替代方法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()丟擲異常,我們就會丟擲一個自定義異常,並帶有訊息:"username is required"。
4. 全域性級別的錯誤處理
到目前為止,我們提供的所有示例都在函式級別上處理了錯誤處理。
但是,我們可以選擇在全域性範圍內處理我們的WebFlux錯誤。 要做到這一點,我們只需要採取兩個步驟:
- 自定義全域性錯誤響應屬性
- 實現全域性錯誤處理程式
我們的處理程式丟擲的異常將被自動轉換為HTTP狀態和JSON錯誤正文。 要自定義這些,我們可以簡單地擴充套件DefaultErrorAttributes類並覆蓋其getErrorAttributes()方法:
public class GlobalErrorAttributes extends DefaultErrorAttributes{
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request,
boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(
request, includeStackTrace);
map.put("status", HttpStatus.BAD_REQUEST);
map.put("message", "username is required");
return map;
}
}
在這裡,我們希望狀態:BAD_REQUEST和訊息:"username is required"在發生異常時作為錯誤屬性的一部分返回。
接下來,讓我們實現全域性錯誤處理程式。 為此,Spring提供了一個方便的AbstractErrorWebExceptionHandler類,供我們在處理全域性錯誤時進行擴充套件和實現:
@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, false);
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(errorPropertiesMap));
}
}
在這個例子中,我們將全域性錯誤處理程式的順序設定為-2。 這是為了給它一個比在@Order(-1)註冊的DefaultErrorWebExceptionHandler更高的優先順序。
errorAttributes物件將是我們在Web異常處理程式的建構函式中傳遞的副本的精確副本。 理想情況下,這應該是我們自定義的Error Attributes類。
然後,我們清楚地說明我們想要將所有錯誤處理請求路由到renderErrorResponse()方法。
最後,我們獲取錯誤屬性並將它們插入伺服器響應主體中。
然後,它會生成一個JSON響應,其中包含錯誤,HTTP狀態和計算機客戶端的異常訊息的詳細資訊。 對於瀏覽器客戶端,它有一個“whitelabel”錯誤處理程式,它以HTML格式呈現相同的資料。 當然,這可以是定製的。
5. 結尾
在本文中,我們研究了可用於處理Spring WebFlux專案中的錯誤的各種策略,並指出了使用一種策略而不是另一種策略的優勢。
正如所承諾的那樣,本文附帶的完整原始碼可以在 GitHub獲得。
相關文章
- 【譯】RxJava 中的錯誤處理RxJava
- 【翻譯】Reactor 第七篇 Spring WebFlux 怎麼進行異常處理ReactSpringWebUX
- [譯] 使用 Catcher 處理 Flutter 錯誤Flutter
- [譯] Go 1.13 errors 包錯誤處理GoError
- 七、Spring Boot 錯誤處理原理 & 定製錯誤頁面Spring Boot
- grpc中的錯誤處理RPC
- Spring boot/Spring 統一錯誤處理方案的使用Spring Boot
- 錯誤處理
- 如何處理 Spring Boot 中與快取相關的錯誤?Spring Boot快取
- Restful API 中的錯誤處理RESTAPI
- 如何優雅的在Golang中進行錯誤處理Golang
- 翻譯 | Java流中如何處理異常Java
- Spring Boot 2 Webflux的全域性異常處理Spring BootWebUX
- Python錯誤處理Python
- PHP 錯誤處理PHP
- php錯誤處理PHP
- Go 錯誤處理Go
- 錯誤處理:如何通過 error、deferred、panic 等處理錯誤?Error
- 談談RxSwift中的錯誤處理Swift
- 應用中的錯誤處理概述
- Bash 指令碼中的錯誤處理指令碼
- 在vue使用異常處理做錯誤提示Vue
- eclipse在使用中彈出這個錯誤框,該如何處理?Eclipse
- 在大型軟體專案中如何處理錯誤和異常
- openGauss 處理錯誤表
- go的錯誤處理Go
- axios 的錯誤處理iOS
- 如何在 Go 中優雅的處理和返回錯誤(1)——函式內部的錯誤處理Go函式
- Python錯誤處理和異常處理(二)Python
- Rust中錯誤處理的最簡單指南Rust
- Oracle異常錯誤處理Oracle
- 淺談前端錯誤處理前端
- ORACLE 異常錯誤處理Oracle
- PHP 核心特性 - 錯誤處理PHP
- 15-錯誤處理(Error)Error
- Go語言之錯誤處理Go
- laravel9 錯誤處理Laravel
- 學習Rust 錯誤處理Rust