diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java index 8e52bb25002c..b306e7299cb1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java @@ -32,10 +32,12 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.util.Assert; import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebHandler; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; @@ -1231,9 +1233,6 @@ public List viewResolvers() { private static class RouterFunctionWebHandler implements WebHandler { - private static final HandlerFunction NOT_FOUND_HANDLER = - request -> ServerResponse.notFound().build(); - private final HandlerStrategies strategies; private final RouterFunction routerFunction; @@ -1249,7 +1248,7 @@ public Mono handle(ServerWebExchange exchange) { ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders()); addAttributes(exchange, request); return this.routerFunction.route(request) - .defaultIfEmpty(notFound()) + .switchIfEmpty(createNotFoundError()) .flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request))) .flatMap(response -> wrapException(() -> response.writeTo(exchange, new HandlerStrategiesResponseContext(this.strategies)))); @@ -1261,9 +1260,9 @@ private void addAttributes(ServerWebExchange exchange, ServerRequest request) { attributes.put(REQUEST_ATTRIBUTE, request); } - @SuppressWarnings("unchecked") - private static HandlerFunction notFound() { - return (HandlerFunction) NOT_FOUND_HANDLER; + private Mono createNotFoundError() { + return Mono.defer(() -> Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, + "No matching router function"))); } private static Mono wrapException(Supplier> supplier) { diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java index 46b29bdf6cd4..ad6bfbdca9f7 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java @@ -16,14 +16,17 @@ package org.springframework.web.reactive.function.server; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseCookie; @@ -191,6 +194,27 @@ public void toHttpHandlerHandlerResponseStatusException() { assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } + @Test + public void toHttpHandlerRouteNotFoundReturnsResponseStatusException() { + HandlerFunction handlerFunction = request -> ServerResponse.accepted().build(); + RouterFunction routerFunction = + RouterFunctions.route(RequestPredicates.GET("/path"), handlerFunction); + + HandlerStrategies handlerStrategies = HandlerStrategies.empty().exceptionHandler((exchange, ex) -> { + exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND); + DataBuffer buffer = exchange.getResponse().bufferFactory().wrap("Custom response".getBytes(StandardCharsets.UTF_8)); + return exchange.getResponse().writeWith(Flux.just(buffer)); + }).build(); + HttpHandler result = RouterFunctions.toHttpHandler(routerFunction, handlerStrategies); + assertThat(result).isNotNull(); + + MockServerHttpRequest httpRequest = MockServerHttpRequest.get("https://localhost").build(); + MockServerHttpResponse httpResponse = new MockServerHttpResponse(); + result.handle(httpRequest, httpResponse).block(); + assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + assertThat(httpResponse.getBodyAsString().block()).isEqualTo("Custom response"); + } + @Test public void toHttpHandlerHandlerReturnResponseStatusExceptionInResponseWriteTo() { HandlerFunction handlerFunction =