diff --git a/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java b/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java index 520965640c74..ff72eb1e465d 100644 --- a/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java +++ b/spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java @@ -16,8 +16,13 @@ package org.springframework.web.client; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.CharBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -25,6 +30,7 @@ import org.springframework.http.client.ClientHttpResponse; import org.springframework.lang.Nullable; import org.springframework.util.FileCopyUtils; +import org.springframework.util.ObjectUtils; /** * Spring's default implementation of the {@link ResponseErrorHandler} interface. @@ -96,12 +102,51 @@ protected boolean hasError(int unknownStatusCode) { public void handleError(ClientHttpResponse response) throws IOException { HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode()); if (statusCode == null) { - throw new UnknownHttpStatusCodeException(response.getRawStatusCode(), response.getStatusText(), + String message = getErrorMessage( + response.getRawStatusCode(), response.getStatusText(), + getResponseBody(response), getCharset(response)); + throw new UnknownHttpStatusCodeException(message, + response.getRawStatusCode(), response.getStatusText(), response.getHeaders(), getResponseBody(response), getCharset(response)); } handleError(response, statusCode); } + /** + * Return error message with details from the response body, possibly truncated: + *
+ * 404 Not Found: [{'id': 123, 'message': 'my very long... (500 bytes)] + *+ */ + private String getErrorMessage( + int rawStatusCode, String statusText, @Nullable byte[] responseBody, @Nullable Charset charset) { + + String preface = rawStatusCode + " " + statusText + ": "; + if (ObjectUtils.isEmpty(responseBody)) { + return preface + "[no body]"; + } + + charset = charset == null ? StandardCharsets.UTF_8 : charset; + int maxChars = 200; + + if (responseBody.length < maxChars * 2) { + return preface + "[" + new String(responseBody, charset) + "]"; + } + + try { + Reader reader = new InputStreamReader(new ByteArrayInputStream(responseBody), charset); + CharBuffer buffer = CharBuffer.allocate(maxChars); + reader.read(buffer); + reader.close(); + buffer.flip(); + return preface + "[" + buffer.toString() + "... (" + responseBody.length + " bytes)]"; + } + catch (IOException ex) { + // should never happen + throw new IllegalStateException(ex); + } + } + /** * Handle the error in the given response with the given resolved status code. *
The default implementation throws an {@link HttpClientErrorException}
@@ -118,13 +163,15 @@ protected void handleError(ClientHttpResponse response, HttpStatus statusCode) t
HttpHeaders headers = response.getHeaders();
byte[] body = getResponseBody(response);
Charset charset = getCharset(response);
+ String message = getErrorMessage(statusCode.value(), statusText, body, charset);
+
switch (statusCode.series()) {
case CLIENT_ERROR:
- throw HttpClientErrorException.create(statusCode, statusText, headers, body, charset);
+ throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
case SERVER_ERROR:
- throw HttpServerErrorException.create(statusCode, statusText, headers, body, charset);
+ throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
default:
- throw new UnknownHttpStatusCodeException(statusCode.value(), statusText, headers, body, charset);
+ throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java b/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java
index a8f3328af2a8..ff6e3f83085a 100644
--- a/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java
+++ b/spring-web/src/main/java/org/springframework/web/client/HttpClientErrorException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,6 +66,17 @@ public HttpClientErrorException(HttpStatus statusCode, String statusText,
super(statusCode, statusText, headers, body, responseCharset);
}
+ /**
+ * Constructor with a status code and status text, headers, and content,
+ * and an prepared message.
+ * @since 5.2.2
+ */
+ public HttpClientErrorException(String message, HttpStatus statusCode, String statusText,
+ @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset responseCharset) {
+
+ super(message, statusCode, statusText, headers, body, responseCharset);
+ }
+
/**
* Create {@code HttpClientErrorException} or an HTTP status specific sub-class.
@@ -74,31 +85,66 @@ public HttpClientErrorException(HttpStatus statusCode, String statusText,
public static HttpClientErrorException create(
HttpStatus statusCode, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ return create(null, statusCode, statusText, headers, body, charset);
+ }
+
+ /**
+ * Variant of {@link #create(HttpStatus, String, HttpHeaders, byte[], Charset)}
+ * with an optional prepared message.
+ * @since 5.2.2
+ */
+ public static HttpClientErrorException create(@Nullable String message, HttpStatus statusCode,
+ String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
switch (statusCode) {
case BAD_REQUEST:
- return new HttpClientErrorException.BadRequest(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.BadRequest(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.BadRequest(statusText, headers, body, charset);
case UNAUTHORIZED:
- return new HttpClientErrorException.Unauthorized(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.Unauthorized(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.Unauthorized(statusText, headers, body, charset);
case FORBIDDEN:
- return new HttpClientErrorException.Forbidden(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.Forbidden(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.Forbidden(statusText, headers, body, charset);
case NOT_FOUND:
- return new HttpClientErrorException.NotFound(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.NotFound(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.NotFound(statusText, headers, body, charset);
case METHOD_NOT_ALLOWED:
- return new HttpClientErrorException.MethodNotAllowed(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.MethodNotAllowed(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.MethodNotAllowed(statusText, headers, body, charset);
case NOT_ACCEPTABLE:
- return new HttpClientErrorException.NotAcceptable(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.NotAcceptable(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.NotAcceptable(statusText, headers, body, charset);
case CONFLICT:
- return new HttpClientErrorException.Conflict(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.Conflict(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.Conflict(statusText, headers, body, charset);
case GONE:
- return new HttpClientErrorException.Gone(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.Gone(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.Gone(statusText, headers, body, charset);
case UNSUPPORTED_MEDIA_TYPE:
- return new HttpClientErrorException.UnsupportedMediaType(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.UnsupportedMediaType(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.UnsupportedMediaType(statusText, headers, body, charset);
case TOO_MANY_REQUESTS:
- return new HttpClientErrorException.TooManyRequests(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.TooManyRequests(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.TooManyRequests(statusText, headers, body, charset);
case UNPROCESSABLE_ENTITY:
- return new HttpClientErrorException.UnprocessableEntity(statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException.UnprocessableEntity(message, statusText, headers, body, charset) :
+ new HttpClientErrorException.UnprocessableEntity(statusText, headers, body, charset);
default:
- return new HttpClientErrorException(statusCode, statusText, headers, body, charset);
+ return message != null ?
+ new HttpClientErrorException(message, statusCode, statusText, headers, body, charset) :
+ new HttpClientErrorException(statusCode, statusText, headers, body, charset);
}
}
@@ -110,11 +156,17 @@ public static HttpClientErrorException create(
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class BadRequest extends HttpClientErrorException {
+ public static final class BadRequest extends HttpClientErrorException {
- BadRequest(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private BadRequest(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.BAD_REQUEST, statusText, headers, body, charset);
}
+
+ private BadRequest(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.BAD_REQUEST, statusText, headers, body, charset);
+ }
}
/**
@@ -122,11 +174,17 @@ public static class BadRequest extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class Unauthorized extends HttpClientErrorException {
+ public static final class Unauthorized extends HttpClientErrorException {
- Unauthorized(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private Unauthorized(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNAUTHORIZED, statusText, headers, body, charset);
}
+
+ private Unauthorized(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.UNAUTHORIZED, statusText, headers, body, charset);
+ }
}
/**
@@ -134,11 +192,17 @@ public static class Unauthorized extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class Forbidden extends HttpClientErrorException {
+ public static final class Forbidden extends HttpClientErrorException {
- Forbidden(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private Forbidden(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.FORBIDDEN, statusText, headers, body, charset);
}
+
+ private Forbidden(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.FORBIDDEN, statusText, headers, body, charset);
+ }
}
/**
@@ -146,11 +210,17 @@ public static class Forbidden extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class NotFound extends HttpClientErrorException {
+ public static final class NotFound extends HttpClientErrorException {
- NotFound(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private NotFound(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_FOUND, statusText, headers, body, charset);
}
+
+ private NotFound(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.NOT_FOUND, statusText, headers, body, charset);
+ }
}
/**
@@ -158,11 +228,17 @@ public static class NotFound extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class MethodNotAllowed extends HttpClientErrorException {
+ public static final class MethodNotAllowed extends HttpClientErrorException {
- MethodNotAllowed(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private MethodNotAllowed(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.METHOD_NOT_ALLOWED, statusText, headers, body, charset);
}
+
+ private MethodNotAllowed(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.METHOD_NOT_ALLOWED, statusText, headers, body, charset);
+ }
}
/**
@@ -170,11 +246,17 @@ public static class MethodNotAllowed extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class NotAcceptable extends HttpClientErrorException {
+ public static final class NotAcceptable extends HttpClientErrorException {
- NotAcceptable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private NotAcceptable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_ACCEPTABLE, statusText, headers, body, charset);
}
+
+ private NotAcceptable(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.NOT_ACCEPTABLE, statusText, headers, body, charset);
+ }
}
/**
@@ -182,11 +264,15 @@ public static class NotAcceptable extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class Conflict extends HttpClientErrorException {
+ public static final class Conflict extends HttpClientErrorException {
- Conflict(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private Conflict(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.CONFLICT, statusText, headers, body, charset);
}
+
+ private Conflict(String message, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ super(message, HttpStatus.CONFLICT, statusText, headers, body, charset);
+ }
}
/**
@@ -194,11 +280,15 @@ public static class Conflict extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class Gone extends HttpClientErrorException {
+ public static final class Gone extends HttpClientErrorException {
- Gone(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private Gone(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.GONE, statusText, headers, body, charset);
}
+
+ private Gone(String message, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ super(message, HttpStatus.GONE, statusText, headers, body, charset);
+ }
}
/**
@@ -206,11 +296,17 @@ public static class Gone extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class UnsupportedMediaType extends HttpClientErrorException {
+ public static final class UnsupportedMediaType extends HttpClientErrorException {
- UnsupportedMediaType(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private UnsupportedMediaType(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, statusText, headers, body, charset);
}
+
+ private UnsupportedMediaType(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.UNSUPPORTED_MEDIA_TYPE, statusText, headers, body, charset);
+ }
}
/**
@@ -218,11 +314,17 @@ public static class UnsupportedMediaType extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class UnprocessableEntity extends HttpClientErrorException {
+ public static final class UnprocessableEntity extends HttpClientErrorException {
- UnprocessableEntity(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private UnprocessableEntity(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.UNPROCESSABLE_ENTITY, statusText, headers, body, charset);
}
+
+ private UnprocessableEntity(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.UNPROCESSABLE_ENTITY, statusText, headers, body, charset);
+ }
}
/**
@@ -230,11 +332,17 @@ public static class UnprocessableEntity extends HttpClientErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class TooManyRequests extends HttpClientErrorException {
+ public static final class TooManyRequests extends HttpClientErrorException {
- TooManyRequests(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private TooManyRequests(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.TOO_MANY_REQUESTS, statusText, headers, body, charset);
}
+
+ private TooManyRequests(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.TOO_MANY_REQUESTS, statusText, headers, body, charset);
+ }
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java b/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java
index b0f7cc85f3f5..d45eb16da9ce 100644
--- a/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java
+++ b/spring-web/src/main/java/org/springframework/web/client/HttpServerErrorException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,27 +66,60 @@ public HttpServerErrorException(HttpStatus statusCode, String statusText,
super(statusCode, statusText, headers, body, charset);
}
+ /**
+ * Constructor with a status code and status text, headers, content, and an
+ * prepared message.
+ * @since 5.2.2
+ */
+ public HttpServerErrorException(String message, HttpStatus statusCode, String statusText,
+ @Nullable HttpHeaders headers, @Nullable byte[] body, @Nullable Charset charset) {
+
+ super(message, statusCode, statusText, headers, body, charset);
+ }
/**
* Create an {@code HttpServerErrorException} or an HTTP status specific sub-class.
* @since 5.1
*/
- public static HttpServerErrorException create(
- HttpStatus statusCode, String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ public static HttpServerErrorException create(HttpStatus statusCode,
+ String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ return create(null, statusCode, statusText, headers, body, charset);
+ }
+
+ /**
+ * Variant of {@link #create(String, HttpStatus, String, HttpHeaders, byte[], Charset)}
+ * with an optional prepared message.
+ * @since 5.2.2.
+ */
+ public static HttpServerErrorException create(@Nullable String message, HttpStatus statusCode,
+ String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
switch (statusCode) {
case INTERNAL_SERVER_ERROR:
- return new HttpServerErrorException.InternalServerError(statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException.InternalServerError(message, statusText, headers, body, charset) :
+ new HttpServerErrorException.InternalServerError(statusText, headers, body, charset);
case NOT_IMPLEMENTED:
- return new HttpServerErrorException.NotImplemented(statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException.NotImplemented(message, statusText, headers, body, charset) :
+ new HttpServerErrorException.NotImplemented(statusText, headers, body, charset);
case BAD_GATEWAY:
- return new HttpServerErrorException.BadGateway(statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException.BadGateway(message, statusText, headers, body, charset) :
+ new HttpServerErrorException.BadGateway(statusText, headers, body, charset);
case SERVICE_UNAVAILABLE:
- return new HttpServerErrorException.ServiceUnavailable(statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException.ServiceUnavailable(message, statusText, headers, body, charset) :
+ new HttpServerErrorException.ServiceUnavailable(statusText, headers, body, charset);
case GATEWAY_TIMEOUT:
- return new HttpServerErrorException.GatewayTimeout(statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException.GatewayTimeout(message, statusText, headers, body, charset) :
+ new HttpServerErrorException.GatewayTimeout(statusText, headers, body, charset);
default:
- return new HttpServerErrorException(statusCode, statusText, headers, body, charset);
+ return message != null ?
+ new HttpServerErrorException(message, statusCode, statusText, headers, body, charset) :
+ new HttpServerErrorException(statusCode, statusText, headers, body, charset);
}
}
@@ -98,11 +131,17 @@ public static HttpServerErrorException create(
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class InternalServerError extends HttpServerErrorException {
+ public static final class InternalServerError extends HttpServerErrorException {
- InternalServerError(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private InternalServerError(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.INTERNAL_SERVER_ERROR, statusText, headers, body, charset);
}
+
+ private InternalServerError(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.INTERNAL_SERVER_ERROR, statusText, headers, body, charset);
+ }
}
/**
@@ -110,11 +149,17 @@ public static class InternalServerError extends HttpServerErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class NotImplemented extends HttpServerErrorException {
+ public static final class NotImplemented extends HttpServerErrorException {
- NotImplemented(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private NotImplemented(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.NOT_IMPLEMENTED, statusText, headers, body, charset);
}
+
+ private NotImplemented(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.NOT_IMPLEMENTED, statusText, headers, body, charset);
+ }
}
/**
@@ -122,11 +167,17 @@ public static class NotImplemented extends HttpServerErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class BadGateway extends HttpServerErrorException {
+ public static final class BadGateway extends HttpServerErrorException {
- BadGateway(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private BadGateway(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.BAD_GATEWAY, statusText, headers, body, charset);
}
+
+ private BadGateway(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.BAD_GATEWAY, statusText, headers, body, charset);
+ }
}
/**
@@ -134,11 +185,17 @@ public static class BadGateway extends HttpServerErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class ServiceUnavailable extends HttpServerErrorException {
+ public static final class ServiceUnavailable extends HttpServerErrorException {
- ServiceUnavailable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private ServiceUnavailable(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.SERVICE_UNAVAILABLE, statusText, headers, body, charset);
}
+
+ private ServiceUnavailable(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.SERVICE_UNAVAILABLE, statusText, headers, body, charset);
+ }
}
/**
@@ -146,11 +203,17 @@ public static class ServiceUnavailable extends HttpServerErrorException {
* @since 5.1
*/
@SuppressWarnings("serial")
- public static class GatewayTimeout extends HttpServerErrorException {
+ public static final class GatewayTimeout extends HttpServerErrorException {
- GatewayTimeout(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+ private GatewayTimeout(String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
super(HttpStatus.GATEWAY_TIMEOUT, statusText, headers, body, charset);
}
+
+ private GatewayTimeout(String message, String statusText,
+ HttpHeaders headers, byte[] body, @Nullable Charset charset) {
+
+ super(message, HttpStatus.GATEWAY_TIMEOUT, statusText, headers, body, charset);
+ }
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java b/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java
index 16715ef81151..b660f15be870 100644
--- a/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java
+++ b/spring-web/src/main/java/org/springframework/web/client/HttpStatusCodeException.java
@@ -83,8 +83,25 @@ protected HttpStatusCodeException(HttpStatus statusCode, String statusText,
protected HttpStatusCodeException(HttpStatus statusCode, String statusText,
@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
- super(getMessage(statusCode, statusText), statusCode.value(), statusText,
- responseHeaders, responseBody, responseCharset);
+ this(getMessage(statusCode, statusText),
+ statusCode, statusText, responseHeaders, responseBody, responseCharset);
+ }
+
+ /**
+ * Construct instance with an {@link HttpStatus}, status text, content, and
+ * a response charset.
+ * @param message the exception message
+ * @param statusCode the status code
+ * @param statusText the status text
+ * @param responseHeaders the response headers, may be {@code null}
+ * @param responseBody the response body content, may be {@code null}
+ * @param responseCharset the response body charset, may be {@code null}
+ * @since 5.2.2
+ */
+ protected HttpStatusCodeException(String message, HttpStatus statusCode, String statusText,
+ @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
+
+ super(message, statusCode.value(), statusText, responseHeaders, responseBody, responseCharset);
this.statusCode = statusCode;
}
diff --git a/spring-web/src/main/java/org/springframework/web/client/UnknownHttpStatusCodeException.java b/spring-web/src/main/java/org/springframework/web/client/UnknownHttpStatusCodeException.java
index ac239513ae90..c7b0319018d4 100644
--- a/spring-web/src/main/java/org/springframework/web/client/UnknownHttpStatusCodeException.java
+++ b/spring-web/src/main/java/org/springframework/web/client/UnknownHttpStatusCodeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,8 +45,23 @@ public class UnknownHttpStatusCodeException extends RestClientResponseException
public UnknownHttpStatusCodeException(int rawStatusCode, String statusText, @Nullable HttpHeaders responseHeaders,
@Nullable byte[] responseBody, @Nullable Charset responseCharset) {
- super("Unknown status code [" + rawStatusCode + "]" + " " + statusText,
+ this("Unknown status code [" + rawStatusCode + "]" + " " + statusText,
rawStatusCode, statusText, responseHeaders, responseBody, responseCharset);
}
+ /**
+ * Construct a new instance of {@code HttpStatusCodeException} based on an
+ * {@link HttpStatus}, status text, and response body content.
+ * @param rawStatusCode the raw status code value
+ * @param statusText the status text
+ * @param responseHeaders the response headers (may be {@code null})
+ * @param responseBody the response body content (may be {@code null})
+ * @param responseCharset the response body charset (may be {@code null})
+ * @since 5.2.2
+ */
+ public UnknownHttpStatusCodeException(String message, int rawStatusCode, String statusText,
+ @Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {
+
+ super(message, rawStatusCode, statusText, responseHeaders, responseBody, responseCharset);
+ }
}
diff --git a/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java b/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java
index e9f782609378..c5c05c48e426 100644
--- a/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java
+++ b/spring-web/src/test/java/org/springframework/web/client/DefaultResponseErrorHandlerTests.java
@@ -19,8 +19,10 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.function.Function;
import org.junit.jupiter.api.Test;
+import reactor.core.publisher.Flux;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -69,9 +71,28 @@ public void handleError() throws Exception {
given(response.getHeaders()).willReturn(headers);
given(response.getBody()).willReturn(new ByteArrayInputStream("Hello World".getBytes(StandardCharsets.UTF_8)));
- assertThatExceptionOfType(HttpClientErrorException.class).isThrownBy(() ->
- handler.handleError(response))
- .satisfies(ex -> assertThat(ex.getResponseHeaders()).isSameAs(headers));
+ assertThatExceptionOfType(HttpClientErrorException.class)
+ .isThrownBy(() -> handler.handleError(response))
+ .satisfies(ex -> assertThat(ex.getResponseHeaders()).isSameAs(headers))
+ .satisfies(ex -> assertThat(ex.getMessage()).isEqualTo("404 Not Found: [Hello World]"));
+ }
+
+ @Test
+ public void handleErrorWithLongBody() throws Exception {
+
+ Function