在Spring WebFlux中处理错误
在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)
{ ute(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 方法:server error啥意思
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 -> (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 =
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
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()方法。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。