diff --git a/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java b/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java index 3275eb8d9661..30acaefb9c11 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java +++ b/spring-web/src/main/java/org/springframework/http/HttpStatusCode.java @@ -88,6 +88,14 @@ default boolean isSameCodeAs(HttpStatusCode other) { return value() == other.value(); } + /** + * Checks whether this status code is a well-known HTTP status code or not + * @return {@code true} if the status code corresponds to a standard HTTP status code, {@code false} otherwise + */ + default boolean isWellKnown() { + return HttpStatus.resolve(this.value()) != null; + } + /** * Return an {@code HttpStatusCode} object for the given integer value. * @param code the status code as integer diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java index 854cba139e80..460dafb2b086 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java @@ -516,9 +516,11 @@ private void initCookies(MultiValueMap out) { private static class DefaultResponseSpec implements ResponseSpec { private static final Predicate STATUS_CODE_ERROR = HttpStatusCode::isError; - - private static final StatusHandler DEFAULT_STATUS_HANDLER = + private static final Predicate STATUS_CODE_UNKNOWN = status -> !status.isWellKnown(); + private static final StatusHandler DEFAULT_ERROR_STATUS_HANDLER = new StatusHandler(STATUS_CODE_ERROR, ClientResponse::createException); + private static final StatusHandler DEFAULT_UNKNOWN_STATUS_HANDLER = + new StatusHandler(STATUS_CODE_UNKNOWN, ClientResponse::createException); private final HttpMethod httpMethod; @@ -537,7 +539,8 @@ private static class DefaultResponseSpec implements ResponseSpec { this.uri = uri; this.responseMono = responseMono; this.statusHandlers.addAll(defaultStatusHandlers); - this.statusHandlers.add(DEFAULT_STATUS_HANDLER); + this.statusHandlers.add(DEFAULT_ERROR_STATUS_HANDLER); + this.statusHandlers.add(DEFAULT_UNKNOWN_STATUS_HANDLER); this.defaultStatusHandlerCount = this.statusHandlers.size(); } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java index 3d7c637f85a7..292c99d3c222 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java @@ -673,6 +673,40 @@ void retrieve555UnknownStatus(ClientHttpConnector connector) { }); } + @ParameterizedWebClientTest + void retrieve929CustomUnknownStatus(ClientHttpConnector connector) { + startServer(connector); + + int errorStatus = 929; + assertThat(HttpStatus.resolve(errorStatus)).isNull(); + String errorMessage = "Something went wrong"; + prepareResponse(response -> response.setResponseCode(errorStatus) + .setHeader("Content-Type", "text/plain").setBody(errorMessage)); + + Mono result = this.webClient.get() + .uri("/unknownPage") + .retrieve() + .bodyToMono(String.class); + + StepVerifier.create(result) + .expectErrorSatisfies(throwable -> { + assertThat(throwable).isInstanceOf(UnknownHttpStatusCodeException.class); + UnknownHttpStatusCodeException ex = (UnknownHttpStatusCodeException) throwable; + assertThat(ex.getMessage()).isEqualTo(("Unknown status code ["+errorStatus+"]")); + assertThat(ex.getStatusCode().value()).isEqualTo(errorStatus); + assertThat(ex.getStatusText()).isEmpty(); + assertThat(ex.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN); + assertThat(ex.getResponseBodyAsString()).isEqualTo(errorMessage); + }) + .verify(Duration.ofSeconds(3)); + + expectRequestCount(1); + expectRequest(request -> { + assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("*/*"); + assertThat(request.getPath()).isEqualTo("/unknownPage"); + }); + } + @ParameterizedWebClientTest void postPojoAsJson(ClientHttpConnector connector) { startServer(connector);