16
16
17
17
package org .springframework .web .client ;
18
18
19
+ import java .io .ByteArrayInputStream ;
19
20
import java .io .IOException ;
20
- import java .net .URI ;
21
+ import java .io .InputStreamReader ;
22
+ import java .io .Reader ;
23
+ import java .nio .CharBuffer ;
21
24
import java .nio .charset .Charset ;
25
+ import java .nio .charset .StandardCharsets ;
22
26
23
27
import org .springframework .http .HttpHeaders ;
24
- import org .springframework .http .HttpMethod ;
25
28
import org .springframework .http .HttpStatus ;
26
29
import org .springframework .http .MediaType ;
27
30
import org .springframework .http .client .ClientHttpResponse ;
28
31
import org .springframework .lang .Nullable ;
29
- import org .springframework .util .Assert ;
30
32
import org .springframework .util .FileCopyUtils ;
33
+ import org .springframework .util .ObjectUtils ;
31
34
32
35
/**
33
36
* Spring's default implementation of the {@link ResponseErrorHandler} interface.
46
49
*/
47
50
public class DefaultResponseErrorHandler implements ResponseErrorHandler {
48
51
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
-
60
52
/**
61
53
* Delegates to {@link #hasError(HttpStatus)} (for a standard status enum value) or
62
54
* {@link #hasError(int)} (for an unknown status code) with the response status code.
@@ -101,31 +93,58 @@ protected boolean hasError(int unknownStatusCode) {
101
93
}
102
94
103
95
/**
104
- * Delegates to {@link #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)} with the
96
+ * Delegates to {@link #handleError(ClientHttpResponse, HttpStatus)} with the
105
97
* response status code.
106
98
* @throws UnknownHttpStatusCodeException in case of an unresolvable status code
107
- * @see #handleError(URI, HttpMethod, ClientHttpResponse, HttpStatus)
99
+ * @see #handleError(ClientHttpResponse, HttpStatus)
108
100
*/
109
101
@ Override
110
102
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 );
112
113
}
113
114
114
115
/**
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>
119
120
*/
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 );
127
147
}
128
- handleError (url , method , response , statusCode );
129
148
}
130
149
131
150
/**
@@ -140,34 +159,19 @@ public void handleError(URI url, HttpMethod method, ClientHttpResponse response)
140
159
* @see HttpServerErrorException#create
141
160
*/
142
161
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
-
157
162
String statusText = response .getStatusText ();
158
163
HttpHeaders headers = response .getHeaders ();
159
164
byte [] body = getResponseBody (response );
160
165
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 );
162
167
163
168
switch (statusCode .series ()) {
164
169
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 );
166
171
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 );
168
173
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 );
171
175
}
172
176
}
173
177
0 commit comments