Skip to content

Commit 04aa3d0

Browse files
committed
Refactor solution for respones error details
See gh-1956
1 parent 91ec274 commit 04aa3d0

11 files changed

+306
-483
lines changed

spring-web/src/main/java/org/springframework/web/client/DefaultHttpErrorDetailsExtractor.java

-138
This file was deleted.

spring-web/src/main/java/org/springframework/web/client/DefaultResponseErrorHandler.java

+52-48
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@
1616

1717
package org.springframework.web.client;
1818

19+
import java.io.ByteArrayInputStream;
1920
import java.io.IOException;
20-
import java.net.URI;
21+
import java.io.InputStreamReader;
22+
import java.io.Reader;
23+
import java.nio.CharBuffer;
2124
import java.nio.charset.Charset;
25+
import java.nio.charset.StandardCharsets;
2226

2327
import org.springframework.http.HttpHeaders;
24-
import org.springframework.http.HttpMethod;
2528
import org.springframework.http.HttpStatus;
2629
import org.springframework.http.MediaType;
2730
import org.springframework.http.client.ClientHttpResponse;
2831
import org.springframework.lang.Nullable;
29-
import org.springframework.util.Assert;
3032
import org.springframework.util.FileCopyUtils;
33+
import org.springframework.util.ObjectUtils;
3134

3235
/**
3336
* Spring's default implementation of the {@link ResponseErrorHandler} interface.
@@ -46,17 +49,6 @@
4649
*/
4750
public class DefaultResponseErrorHandler implements ResponseErrorHandler {
4851

49-
private HttpErrorDetailsExtractor httpErrorDetailsExtractor = new DefaultHttpErrorDetailsExtractor();
50-
51-
/**
52-
* Set the error summary extractor.
53-
* <p>By default, DefaultResponseErrorHandler uses a {@link DefaultHttpErrorDetailsExtractor}.
54-
*/
55-
public void setHttpErrorDetailsExtractor(HttpErrorDetailsExtractor httpErrorDetailsExtractor) {
56-
Assert.notNull(httpErrorDetailsExtractor, "HttpErrorDetailsExtractor must not be null");
57-
this.httpErrorDetailsExtractor = httpErrorDetailsExtractor;
58-
}
59-
6052
/**
6153
* Delegates to {@link #hasError(HttpStatus)} (for a standard status enum value) or
6254
* {@link #hasError(int)} (for an unknown status code) with the response status code.
@@ -101,31 +93,58 @@ protected boolean hasError(int unknownStatusCode) {
10193
}
10294

10395
/**
104-
* Delegates to {@link #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)} with the
96+
* Delegates to {@link #handleError(ClientHttpResponse, HttpStatus)} with the
10597
* response status code.
10698
* @throws UnknownHttpStatusCodeException in case of an unresolvable status code
107-
* @see #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)
99+
* @see #handleError(ClientHttpResponse, HttpStatus)
108100
*/
109101
@Override
110102
public void handleError(ClientHttpResponse response) throws IOException {
111-
handleError(null, null, response);
103+
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
104+
if (statusCode == null) {
105+
String message = getErrorMessage(
106+
response.getRawStatusCode(), response.getStatusText(),
107+
getResponseBody(response), getCharset(response));
108+
throw new UnknownHttpStatusCodeException(message,
109+
response.getRawStatusCode(), response.getStatusText(),
110+
response.getHeaders(), getResponseBody(response), getCharset(response));
111+
}
112+
handleError(response, statusCode);
112113
}
113114

114115
/**
115-
* Delegates to {@link #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)} with the
116-
* response status code.
117-
* @throws UnknownHttpStatusCodeException in case of an unresolvable status code
118-
* @see #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)
116+
* Return error message with details from the response body, possibly truncated:
117+
* <pre>
118+
* 404 Not Found: [{'id': 123, 'message': 'my very long... (500 bytes)]
119+
* </pre>
119120
*/
120-
@Override
121-
public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
122-
HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
123-
if (statusCode == null) {
124-
String message = httpErrorDetailsExtractor.getErrorDetails(response.getRawStatusCode(), response.getStatusText(), getResponseBody(response), getCharset(response), url, method);
125-
throw new UnknownHttpStatusCodeException(message, response.getRawStatusCode(), response.getStatusText(),
126-
response.getHeaders(), getResponseBody(response), getCharset(response), url, method);
121+
private String getErrorMessage(
122+
int rawStatusCode, String statusText, @Nullable byte[] responseBody, @Nullable Charset charset) {
123+
124+
String preface = rawStatusCode + " " + statusText + ": ";
125+
if (ObjectUtils.isEmpty(responseBody)) {
126+
return preface + "[no body]";
127+
}
128+
129+
charset = charset == null ? StandardCharsets.UTF_8 : charset;
130+
int maxChars = 200;
131+
132+
if (responseBody.length < maxChars * 2) {
133+
return preface + "[" + new String(responseBody, charset) + "]";
134+
}
135+
136+
try {
137+
Reader reader = new InputStreamReader(new ByteArrayInputStream(responseBody), charset);
138+
CharBuffer buffer = CharBuffer.allocate(maxChars);
139+
reader.read(buffer);
140+
reader.close();
141+
buffer.flip();
142+
return preface + "[" + buffer.toString() + "... (" + responseBody.length + " bytes)]";
143+
}
144+
catch (IOException ex) {
145+
// should never happen
146+
throw new IllegalStateException(ex);
127147
}
128-
handleError(url, method, response, statusCode);
129148
}
130149

131150
/**
@@ -140,34 +159,19 @@ public void handleError(URI url, HttpMethod method, ClientHttpResponse response)
140159
* @see HttpServerErrorException#create
141160
*/
142161
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
143-
handleError(null, null, response, statusCode);
144-
}
145-
146-
/**
147-
* Handle the error in the given response with the given resolved status code.
148-
* <p>This default implementation throws a {@link HttpClientErrorException} if the response status code
149-
* is {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR}, a {@link HttpServerErrorException}
150-
* if it is {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR},
151-
* and a {@link RestClientException} in other cases.
152-
* @since 5.0
153-
*/
154-
protected void handleError(@Nullable URI url, @Nullable HttpMethod method, ClientHttpResponse response,
155-
HttpStatus statusCode) throws IOException {
156-
157162
String statusText = response.getStatusText();
158163
HttpHeaders headers = response.getHeaders();
159164
byte[] body = getResponseBody(response);
160165
Charset charset = getCharset(response);
161-
String message = httpErrorDetailsExtractor.getErrorDetails(statusCode.value(), statusText, body, charset, url, method);
166+
String message = getErrorMessage(statusCode.value(), statusText, body, charset);
162167

163168
switch (statusCode.series()) {
164169
case CLIENT_ERROR:
165-
throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset, url, method);
170+
throw HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset);
166171
case SERVER_ERROR:
167-
throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset, url, method);
172+
throw HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset);
168173
default:
169-
throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body,
170-
charset, url, method);
174+
throw new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset);
171175
}
172176
}
173177

0 commit comments

Comments
 (0)