Browse Source

Use DispatchExceptionHandler for handler errors

See gh-30930
pull/30963/head
Rossen Stoyanchev 3 years ago committed by rstoyanchev
parent
commit
85704c890e
  1. 3
      spring-webflux/src/main/java/org/springframework/web/reactive/DispatchExceptionHandler.java
  2. 59
      spring-webflux/src/main/java/org/springframework/web/reactive/DispatcherHandler.java

3
spring-webflux/src/main/java/org/springframework/web/reactive/DispatchExceptionHandler.java

@ -29,7 +29,8 @@ import org.springframework.web.server.ServerWebExchange;
* a {@link HandlerAdapter} to apply its exception handling to deferred exceptions * a {@link HandlerAdapter} to apply its exception handling to deferred exceptions
* from asynchronous return values, and to response rendering. * from asynchronous return values, and to response rendering.
* <li>Implemented by a {@link HandlerAdapter} in order to handle exceptions that * <li>Implemented by a {@link HandlerAdapter} in order to handle exceptions that
* occur before a request is mapped to a handler. * occur before a request is mapped to a handler, or for unhandled errors from a
* handler..
* </ul> * </ul>
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev

59
spring-webflux/src/main/java/org/springframework/web/reactive/DispatcherHandler.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -150,7 +150,7 @@ public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, A
.concatMap(mapping -> mapping.getHandler(exchange)) .concatMap(mapping -> mapping.getHandler(exchange))
.next() .next()
.switchIfEmpty(createNotFoundError()) .switchIfEmpty(createNotFoundError())
.onErrorResume(ex -> handleDispatchError(exchange, ex)) .onErrorResume(ex -> handleResultMono(exchange, Mono.error(ex)))
.flatMap(handler -> handleRequestWith(exchange, handler)); .flatMap(handler -> handleRequestWith(exchange, handler));
} }
@ -161,8 +161,7 @@ public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, A
}); });
} }
private Mono<Void> handleDispatchError(ServerWebExchange exchange, Throwable ex) { private Mono<Void> handleResultMono(ServerWebExchange exchange, Mono<HandlerResult> resultMono) {
Mono<HandlerResult> resultMono = Mono.error(ex);
if (this.handlerAdapters != null) { if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) { for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter instanceof DispatchExceptionHandler exceptionHandler) { if (adapter instanceof DispatchExceptionHandler exceptionHandler) {
@ -170,36 +169,19 @@ public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, A
} }
} }
} }
return resultMono.flatMap(result -> handleResult(exchange, result)); return resultMono.flatMap(result -> {
} Mono<Void> voidMono = handleResult(exchange, result, "Handler " + result.getHandler());
if (result.getExceptionHandler() != null) {
private Mono<Void> handleRequestWith(ServerWebExchange exchange, Object handler) { voidMono = voidMono.onErrorResume(ex ->
if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) { result.getExceptionHandler().handleError(exchange, ex).flatMap(result2 ->
return Mono.empty(); // CORS rejection handleResult(exchange, result2, "Exception handler " +
} result2.getHandler() + ", error=\"" + ex.getMessage() + "\"")));
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter.handle(exchange, handler)
.flatMap(result -> handleResult(exchange, result));
}
} }
} return voidMono;
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler)); });
}
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Mono<Void> resultMono = doHandleResult(exchange, result, "Handler " + result.getHandler());
if (result.getExceptionHandler() != null) {
resultMono = resultMono.onErrorResume(ex ->
result.getExceptionHandler().handleError(exchange, ex).flatMap(result2 ->
doHandleResult(exchange, result2, "Exception handler " +
result2.getHandler() + ", error=\"" + ex.getMessage() + "\"")));
}
return resultMono;
} }
private Mono<Void> doHandleResult( private Mono<Void> handleResult(
ServerWebExchange exchange, HandlerResult handlerResult, String description) { ServerWebExchange exchange, HandlerResult handlerResult, String description) {
if (this.resultHandlers != null) { if (this.resultHandlers != null) {
@ -214,6 +196,21 @@ public class DispatcherHandler implements WebHandler, PreFlightRequestHandler, A
"No HandlerResultHandler for " + handlerResult.getReturnValue())); "No HandlerResultHandler for " + handlerResult.getReturnValue()));
} }
private Mono<Void> handleRequestWith(ServerWebExchange exchange, Object handler) {
if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {
return Mono.empty(); // CORS rejection
}
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
Mono<HandlerResult> resultMono = adapter.handle(exchange, handler);
return handleResultMono(exchange, resultMono);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
@Override @Override
public Mono<Void> handlePreFlight(ServerWebExchange exchange) { public Mono<Void> handlePreFlight(ServerWebExchange exchange) {
return Flux.fromIterable(this.handlerMappings != null ? this.handlerMappings : Collections.emptyList()) return Flux.fromIterable(this.handlerMappings != null ? this.handlerMappings : Collections.emptyList())

Loading…
Cancel
Save