1 概览
在本教程中,咱们将通过一个理论示例理解 Spring WebFlux 我的项目中处理错误的各种策略。
咱们还将指出应用一种策略比另一种策略更无利的中央,并在最初提供残缺源代码的链接。
2 开始示例代码
maven 设置和之前介绍 Spring WebFlux 的文章一样,
对于咱们的示例,咱们将应用一个 RESTful 端点,它将用户名作为查问参数并返回“Hello username”作为后果。首先,让咱们创立一个路由函数,这个路由函数将“/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)
//...
}
最初,实现 sayHello 办法,实现很简略,间接拼接 hello 和参数 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 参数,咱们的申请就能失常返回。举个例子:咱们申请“/hello?username=Tonni”,相似申请,咱们总是能失常返回。
然而,如果咱们的申请不带 username 参数,咱们的申请就会抛出异样了。上面,咱们来看看 Spring 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)
.bodyValue(s));
}
这里,每当有问题的连贯函数抛出异样的时候,咱们间接返回一个动态后果:“Hello Stranger”。
3.2 onErrorResume 解决异样
有三种应用 onErrorResume 解决异样的形式:
- 计算动静回调值
- 通过回调函数执行其余分支
- 捕捉、包装并从新抛出谬误,例如,作为自定义业务异样
让咱们看看怎么计算值:
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())”。
接下来,咱们看看当异样产生调用回调函数:
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 抛出异样的时候,咱们执行一个其余函数 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”。
全局解决异样
目前为止,咱们提供的所有示例都在办法级别上解决了错误处理。然而咱们能够抉择在全局层面解决异样。为此,咱们只须要两步:
- 自定义一个全局谬误响应属性
- 实现全局错误处理 handler
这样咱们程序抛出的异样将会主动转换成 HTTP 状态和 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 状态码和“username is required”错误信息作为谬误属性的一部分。
而后,咱们来实现全局错误处理 handler。
为此,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,
ErrorAttributeOptions.defaults());
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(errorPropertiesMap));
}
}
在这个例子中,咱们设置 handler 的 order 为 -2。这是为了给它一个比默认 handler,也就是 DefaultErrorWebExceptionHandler 一个更高的优先级,它设置的 order 为 -1。
errorAttributes 对象将是咱们在 Web 异样处理程序的构造函数中传递的对象的准确正本。现实状况下,这应该是咱们自定义的谬误属性类。
而后咱们明确生命了,咱们心愿将所有的异样解决路由到 renderErrorResponse() 中。
最初,咱们获取了谬误属性并插入到服务端响应体中。
而后这会生成一个 JSON 响应,其中蕴含了谬误的详细信息,HTTP 状态、机器端的异样信息等。对于浏览器端,它有一个“white-label”谬误处理程序,能够以 HTML 模式出现雷同的数据,当然这个页面能够定制。
总结
在本文中,咱们钻研了在 Spring WebFlux 我的项目中解决异样的集中策略,并指出应用一个策略优于其余策略的中央。
源码在 github 上
原文:https://www.baeldung.com/spri…