Support non-standard error codes with AbstractErrorWebExceptionHandler
Fixes gh-16691
This commit is contained in:
parent
a695e062d1
commit
4b4dc28a86
|
|
@ -62,6 +62,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
|||
* Currently duplicated from Spring WebFlux HttpWebHandlerAdapter.
|
||||
*/
|
||||
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS;
|
||||
|
||||
static {
|
||||
Set<String> exceptions = new HashSet<>();
|
||||
exceptions.add("AbortedException");
|
||||
|
|
@ -276,7 +277,8 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
|||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(request.exchange().getLogPrefix() + formatError(throwable, request));
|
||||
}
|
||||
if (response.statusCode().equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
|
||||
if (HttpStatus.resolve(response.rawStatusCode()) != null
|
||||
&& response.statusCode().equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
|
||||
logger.error(request.exchange().getLogPrefix() + "500 Server Error for " + formatRequest(request),
|
||||
throwable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.autoconfigure.web.reactive.error;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
|
@ -113,16 +114,26 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
|
||||
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.TEXT_HTML);
|
||||
Map<String, Object> error = getErrorAttributes(request, includeStackTrace);
|
||||
HttpStatus errorStatus = getHttpStatus(error);
|
||||
int errorStatus = getHttpStatus(error);
|
||||
ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus).contentType(TEXT_HTML_UTF8);
|
||||
return Flux
|
||||
.just("error/" + errorStatus.value(), "error/" + SERIES_VIEWS.get(errorStatus.series()), "error/error")
|
||||
return Flux.just(getData(errorStatus).toArray(new String[] {}))
|
||||
.flatMap((viewName) -> renderErrorView(viewName, responseBody, error))
|
||||
.switchIfEmpty(this.errorProperties.getWhitelabel().isEnabled()
|
||||
? renderDefaultErrorView(responseBody, error) : Mono.error(getError(request)))
|
||||
.next();
|
||||
}
|
||||
|
||||
private List<String> getData(int errorStatus) {
|
||||
HttpStatus errorHttpStatus = HttpStatus.resolve(errorStatus);
|
||||
List<String> data = new ArrayList<>();
|
||||
data.add("error/" + errorStatus);
|
||||
if (errorHttpStatus != null) {
|
||||
data.add("error/" + SERIES_VIEWS.get(errorHttpStatus.series()));
|
||||
}
|
||||
data.add("error/error");
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the error information as a JSON payload.
|
||||
* @param request the current request
|
||||
|
|
@ -157,9 +168,8 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
* @param errorAttributes the current error information
|
||||
* @return the error HTTP status
|
||||
*/
|
||||
protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
|
||||
int statusCode = (int) errorAttributes.get("status");
|
||||
return HttpStatus.valueOf(statusCode);
|
||||
protected int getHttpStatus(Map<String, Object> errorAttributes) {
|
||||
return (int) errorAttributes.get("status");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,17 +16,37 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.web.reactive.error;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.web.ErrorProperties;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
|
||||
import org.springframework.boot.web.reactive.error.ErrorAttributes;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.reactive.result.view.View;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link AbstractErrorWebExceptionHandler}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class DefaultErrorWebExceptionHandlerTests {
|
||||
|
||||
|
|
@ -39,4 +59,31 @@ class DefaultErrorWebExceptionHandlerTests {
|
|||
assertThat(errorHandlers).isNotNull().isEqualTo(webHandlers);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonStandardErrorStatusCodeShouldNotFail() {
|
||||
ErrorAttributes errorAttributes = mock(ErrorAttributes.class);
|
||||
ResourceProperties resourceProperties = new ResourceProperties();
|
||||
ErrorProperties errorProperties = new ErrorProperties();
|
||||
ApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();
|
||||
given(errorAttributes.getErrorAttributes(any(), anyBoolean())).willReturn(getErrorAttributes());
|
||||
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
|
||||
resourceProperties, errorProperties, context);
|
||||
setupViewResolver(exceptionHandler);
|
||||
ServerWebExchange exchange = MockServerWebExchange
|
||||
.from(MockServerHttpRequest.get("/some-other-path").accept(MediaType.TEXT_HTML));
|
||||
exceptionHandler.handle(exchange, new RuntimeException()).block();
|
||||
}
|
||||
|
||||
private Map<String, Object> getErrorAttributes() {
|
||||
return Collections.singletonMap("status", 498);
|
||||
}
|
||||
|
||||
private void setupViewResolver(DefaultErrorWebExceptionHandler exceptionHandler) {
|
||||
View view = mock(View.class);
|
||||
given(view.render(any(), any(), any())).willReturn(Mono.empty());
|
||||
ViewResolver viewResolver = mock(ViewResolver.class);
|
||||
given(viewResolver.resolveViewName(any(), any())).willReturn(Mono.just(view));
|
||||
exceptionHandler.setViewResolvers(Collections.singletonList(viewResolver));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue