1616
1717package org .springframework .web .client ;
1818
19+ import java .io .ByteArrayInputStream ;
1920import java .io .IOException ;
20- import java .net .URI ;
21+ import java .io .InputStreamReader ;
22+ import java .io .Reader ;
23+ import java .nio .CharBuffer ;
2124import java .nio .charset .Charset ;
25+ import java .nio .charset .StandardCharsets ;
2226
2327import org .springframework .http .HttpHeaders ;
24- import org .springframework .http .HttpMethod ;
2528import org .springframework .http .HttpStatus ;
2629import org .springframework .http .MediaType ;
2730import org .springframework .http .client .ClientHttpResponse ;
2831import org .springframework .lang .Nullable ;
29- import org .springframework .util .Assert ;
3032import org .springframework .util .FileCopyUtils ;
33+ import org .springframework .util .ObjectUtils ;
3134
3235/**
3336 * Spring's default implementation of the {@link ResponseErrorHandler} interface.
4649 */
4750public 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