Browse Source

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
pull/27832/head
Arjen Poutsma 4 years ago
parent
commit
2f557d9583
  1. 13
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java
  2. 24
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RouterFunctionsTests.java

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

@ -32,10 +32,12 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.server.reactive.HttpHandler; import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.reactive.result.view.ViewResolver; 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.ServerWebExchange;
import org.springframework.web.server.WebHandler; import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
@ -1231,9 +1233,6 @@ public abstract class RouterFunctions {
private static class RouterFunctionWebHandler implements WebHandler { private static class RouterFunctionWebHandler implements WebHandler {
private static final HandlerFunction<ServerResponse> NOT_FOUND_HANDLER =
request -> ServerResponse.notFound().build();
private final HandlerStrategies strategies; private final HandlerStrategies strategies;
private final RouterFunction<?> routerFunction; private final RouterFunction<?> routerFunction;
@ -1249,7 +1248,7 @@ public abstract class RouterFunctions {
ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders()); ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders());
addAttributes(exchange, request); addAttributes(exchange, request);
return this.routerFunction.route(request) return this.routerFunction.route(request)
.defaultIfEmpty(notFound()) .switchIfEmpty(createNotFoundError())
.flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request))) .flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request)))
.flatMap(response -> wrapException(() -> response.writeTo(exchange, .flatMap(response -> wrapException(() -> response.writeTo(exchange,
new HandlerStrategiesResponseContext(this.strategies)))); new HandlerStrategiesResponseContext(this.strategies))));
@ -1261,9 +1260,9 @@ public abstract class RouterFunctions {
attributes.put(REQUEST_ATTRIBUTE, request); attributes.put(REQUEST_ATTRIBUTE, request);
} }
@SuppressWarnings("unchecked") private <R> Mono<R> createNotFoundError() {
private static <T extends ServerResponse> HandlerFunction<T> notFound() { return Mono.defer(() -> Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND,
return (HandlerFunction<T>) NOT_FOUND_HANDLER; "No matching router function")));
} }
private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) { private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) {

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

@ -16,14 +16,17 @@
package org.springframework.web.reactive.function.server; package org.springframework.web.reactive.function.server;
import java.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
@ -191,6 +194,27 @@ public class RouterFunctionsTests {
assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); assertThat(httpResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
} }
@Test
public void toHttpHandlerRouteNotFoundReturnsResponseStatusException() {
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.accepted().build();
RouterFunction<ServerResponse> 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 @Test
public void toHttpHandlerHandlerReturnResponseStatusExceptionInResponseWriteTo() { public void toHttpHandlerHandlerReturnResponseStatusExceptionInResponseWriteTo() {
HandlerFunction<ServerResponse> handlerFunction = HandlerFunction<ServerResponse> handlerFunction =

Loading…
Cancel
Save