Skip to content

Commit

Permalink
Throw 404 ResponseStatusException when no routes found
Browse files Browse the repository at this point in the history
This commit makes it possible to customize 404 responses generated by
RouterFunctionWebHandler, by throwing an ResponseStatusException
instead of returning a standard 404 response.

See gh-25358
  • Loading branch information
ivd-git authored and poutsma committed Dec 3, 2021
1 parent 5649a6f commit 69df27a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1231,9 +1233,6 @@ public List<ViewResolver> viewResolvers() {

private static class RouterFunctionWebHandler implements WebHandler {

private static final HandlerFunction<ServerResponse> NOT_FOUND_HANDLER =
request -> ServerResponse.notFound().build();

private final HandlerStrategies strategies;

private final RouterFunction<?> routerFunction;
Expand All @@ -1249,7 +1248,7 @@ public Mono<Void> handle(ServerWebExchange exchange) {
ServerRequest request = new DefaultServerRequest(exchange, this.strategies.messageReaders());
addAttributes(exchange, request);
return this.routerFunction.route(request)
.defaultIfEmpty(notFound())
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.flatMap(handlerFunction -> wrapException(() -> handlerFunction.handle(request)))
.flatMap(response -> wrapException(() -> response.writeTo(exchange,
new HandlerStrategiesResponseContext(this.strategies))));
Expand All @@ -1261,11 +1260,6 @@ private void addAttributes(ServerWebExchange exchange, ServerRequest request) {
attributes.put(REQUEST_ATTRIBUTE, request);
}

@SuppressWarnings("unchecked")
private static <T extends ServerResponse> HandlerFunction<T> notFound() {
return (HandlerFunction<T>) NOT_FOUND_HANDLER;
}

private static <T> Mono<T> wrapException(Supplier<Mono<T>> supplier) {
try {
return supplier.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -191,6 +194,27 @@ public void toHttpHandlerHandlerResponseStatusException() {
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
public void toHttpHandlerHandlerReturnResponseStatusExceptionInResponseWriteTo() {
HandlerFunction<ServerResponse> handlerFunction =
Expand Down

0 comments on commit 69df27a

Please sign in to comment.