Skip to content

Commit 2f557d9

Browse files
committed
Merge pull request #25358 from ivd-git:router-function-handler-not-found-to-exception-pr
* gh-25358: Polish "Throw 404 ResponseStatusException when no routes found" Throw 404 ResponseStatusException when no routes found
2 parents 5649a6f + b84fe99 commit 2f557d9

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@
3232
import reactor.core.publisher.Mono;
3333

3434
import org.springframework.core.io.Resource;
35+
import org.springframework.http.HttpStatus;
3536
import org.springframework.http.codec.HttpMessageWriter;
3637
import org.springframework.http.server.reactive.HttpHandler;
3738
import org.springframework.util.Assert;
3839
import org.springframework.web.reactive.result.view.ViewResolver;
40+
import org.springframework.web.server.ResponseStatusException;
3941
import org.springframework.web.server.ServerWebExchange;
4042
import org.springframework.web.server.WebHandler;
4143
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
@@ -1231,9 +1233,6 @@ public List<ViewResolver> viewResolvers() {
12311233

12321234
private static class RouterFunctionWebHandler implements WebHandler {
12331235

1234-
private static final HandlerFunction<ServerResponse> NOT_FOUND_HANDLER =
1235-
request -> ServerResponse.notFound().build();
1236-
12371236
private final HandlerStrategies strategies;
12381237

12391238
private final RouterFunction<?> routerFunction;
@@ -1249,7 +1248,7 @@ public Mono<Void> handle(ServerWebExchange exchange) {
12491248
ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders());
12501249
addAttributes(exchange, request);
12511250
return this.routerFunction.route(request)
1252-
.defaultIfEmpty(notFound())
1251+
.switchIfEmpty(createNotFoundError())
12531252
.flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request)))
12541253
.flatMap(response -> wrapException(() -> response.writeTo(exchange,
12551254
new HandlerStrategiesResponseContext(this.strategies))));
@@ -1261,9 +1260,9 @@ private void addAttributes(ServerWebExchange exchange, ServerRequest request) {
12611260
attributes.put(REQUEST_ATTRIBUTE, request);
12621261
}
12631262

1264-
@SuppressWarnings("unchecked")
1265-
private static <T extends ServerResponse> HandlerFunction<T> notFound() {
1266-
return (HandlerFunction<T>) NOT_FOUND_HANDLER;
1263+
private <R> Mono<R> createNotFoundError() {
1264+
return Mono.defer(() -> Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND,
1265+
"No matching router function")));
12671266
}
12681267

12691268
private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) {

spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616

1717
package org.springframework.web.reactive.function.server;
1818

19+
import java.nio.charset.StandardCharsets;
1920
import java.util.Collections;
2021
import java.util.Optional;
2122
import java.util.concurrent.atomic.AtomicBoolean;
2223

2324
import org.junit.jupiter.api.Test;
25+
import reactor.core.publisher.Flux;
2426
import reactor.core.publisher.Mono;
2527
import reactor.test.StepVerifier;
2628

29+
import org.springframework.core.io.buffer.DataBuffer;
2730
import org.springframework.http.HttpHeaders;
2831
import org.springframework.http.HttpStatus;
2932
import org.springframework.http.ResponseCookie;
@@ -191,6 +194,27 @@ public void toHttpHandlerHandlerResponseStatusException() {
191194
assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
192195
}
193196

197+
@Test
198+
public void toHttpHandlerRouteNotFoundReturnsResponseStatusException() {
199+
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.accepted().build();
200+
RouterFunction<ServerResponse> routerFunction =
201+
RouterFunctions.route(RequestPredicates.GET("/path"), handlerFunction);
202+
203+
HandlerStrategies handlerStrategies = HandlerStrategies.empty().exceptionHandler((exchange, ex) -> {
204+
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
205+
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap("Custom response".getBytes(StandardCharsets.UTF_8));
206+
return exchange.getResponse().writeWith(Flux.just(buffer));
207+
}).build();
208+
HttpHandler result = RouterFunctions.toHttpHandler(routerFunction, handlerStrategies);
209+
assertThat(result).isNotNull();
210+
211+
MockServerHttpRequest httpRequest = MockServerHttpRequest.get("https://localhost").build();
212+
MockServerHttpResponse httpResponse = new MockServerHttpResponse();
213+
result.handle(httpRequest, httpResponse).block();
214+
assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
215+
assertThat(httpResponse.getBodyAsString().block()).isEqualTo("Custom response");
216+
}
217+
194218
@Test
195219
public void toHttpHandlerHandlerReturnResponseStatusExceptionInResponseWriteTo() {
196220
HandlerFunction<ServerResponse> handlerFunction =

0 commit comments

Comments
 (0)