1
1
/*
2
- * Copyright 2002-2022 the original author or authors.
2
+ * Copyright 2002-2024 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
19
19
import java .io .ByteArrayInputStream ;
20
20
import java .io .IOException ;
21
21
import java .io .InputStream ;
22
+ import java .net .URI ;
22
23
import java .nio .charset .Charset ;
23
24
import java .nio .charset .StandardCharsets ;
24
25
import java .util .Collections ;
28
29
import org .springframework .core .ResolvableType ;
29
30
import org .springframework .core .log .LogFormatUtils ;
30
31
import org .springframework .http .HttpHeaders ;
32
+ import org .springframework .http .HttpMethod ;
31
33
import org .springframework .http .HttpStatus ;
32
34
import org .springframework .http .HttpStatusCode ;
33
35
import org .springframework .http .MediaType ;
@@ -129,35 +131,74 @@ protected boolean hasError(int statusCode) {
129
131
* {@link HttpStatus} enum range.
130
132
* </ul>
131
133
* @throws UnknownHttpStatusCodeException in case of an unresolvable status code
132
- * @see #handleError(ClientHttpResponse, HttpStatusCode)
134
+ * @see #handleError(ClientHttpResponse, HttpStatusCode, URI, HttpMethod )
133
135
*/
134
136
@ Override
135
137
public void handleError (ClientHttpResponse response ) throws IOException {
136
138
HttpStatusCode statusCode = response .getStatusCode ();
137
- handleError (response , statusCode );
139
+ handleError (response , statusCode , null , null );
140
+ }
141
+
142
+ /**
143
+ * Handle the error in the given response with the given resolved status code
144
+ * and extra information providing access to the request URL and HTTP method.
145
+ * <p>The default implementation throws:
146
+ * <ul>
147
+ * <li>{@link HttpClientErrorException} if the status code is in the 4xx
148
+ * series, or one of its sub-classes such as
149
+ * {@link HttpClientErrorException.BadRequest} and others.
150
+ * <li>{@link HttpServerErrorException} if the status code is in the 5xx
151
+ * series, or one of its sub-classes such as
152
+ * {@link HttpServerErrorException.InternalServerError} and others.
153
+ * <li>{@link UnknownHttpStatusCodeException} for error status codes not in the
154
+ * {@link HttpStatus} enum range.
155
+ * </ul>
156
+ * @throws UnknownHttpStatusCodeException in case of an unresolvable status code
157
+ * @since 6.2
158
+ * @see #handleError(ClientHttpResponse, HttpStatusCode, URI, HttpMethod)
159
+ */
160
+ @ Override
161
+ public void handleError (URI url , HttpMethod method , ClientHttpResponse response ) throws IOException {
162
+ HttpStatusCode statusCode = response .getStatusCode ();
163
+ handleError (response , statusCode , url , method );
138
164
}
139
165
140
166
/**
141
167
* Return error message with details from the response body. For example:
142
168
* <pre>
143
- * 404 Not Found: [{'id': 123, 'message': 'my message'}]
169
+ * 404 Not Found on GET request for "https://example.com" : [{'id': 123, 'message': 'my message'}]
144
170
* </pre>
145
171
*/
146
- private String getErrorMessage (
147
- int rawStatusCode , String statusText , @ Nullable byte [] responseBody , @ Nullable Charset charset ) {
148
-
149
- String preface = rawStatusCode + " " + statusText + ": " ;
172
+ private String getErrorMessage (int rawStatusCode , String statusText , @ Nullable byte [] responseBody , @ Nullable Charset charset ,
173
+ @ Nullable URI url , @ Nullable HttpMethod method ) {
150
174
175
+ StringBuilder msg = new StringBuilder (rawStatusCode + " " + statusText );
176
+ if (method != null ) {
177
+ msg .append (" on " ).append (method ).append (" request" );
178
+ }
179
+ if (url != null ) {
180
+ msg .append (" for \" " );
181
+ String urlString = url .toString ();
182
+ int idx = urlString .indexOf ('?' );
183
+ if (idx != -1 ) {
184
+ msg .append (urlString , 0 , idx );
185
+ }
186
+ else {
187
+ msg .append (urlString );
188
+ }
189
+ msg .append ("\" " );
190
+ }
191
+ msg .append (": " );
151
192
if (ObjectUtils .isEmpty (responseBody )) {
152
- return preface + "[no body]" ;
193
+ msg . append ( "[no body]" ) ;
153
194
}
154
-
155
- charset = (charset != null ? charset : StandardCharsets .UTF_8 );
156
-
157
- String bodyText = new String ( responseBody , charset );
158
- bodyText = LogFormatUtils . formatValue (bodyText , - 1 , true );
159
-
160
- return preface + bodyText ;
195
+ else {
196
+ charset = (charset != null ? charset : StandardCharsets .UTF_8 );
197
+ String bodyText = new String ( responseBody , charset );
198
+ bodyText = LogFormatUtils . formatValue ( bodyText , - 1 , true );
199
+ msg . append (bodyText );
200
+ }
201
+ return msg . toString () ;
161
202
}
162
203
163
204
/**
@@ -167,16 +208,16 @@ private String getErrorMessage(
167
208
* {@link HttpClientErrorException#create} for errors in the 4xx range, to
168
209
* {@link HttpServerErrorException#create} for errors in the 5xx range,
169
210
* or otherwise raises {@link UnknownHttpStatusCodeException}.
170
- * @since 5.0
211
+ * @since 6.2
171
212
* @see HttpClientErrorException#create
172
213
* @see HttpServerErrorException#create
173
214
*/
174
- protected void handleError (ClientHttpResponse response , HttpStatusCode statusCode ) throws IOException {
215
+ protected void handleError (ClientHttpResponse response , HttpStatusCode statusCode , @ Nullable URI url , @ Nullable HttpMethod method ) throws IOException {
175
216
String statusText = response .getStatusText ();
176
217
HttpHeaders headers = response .getHeaders ();
177
218
byte [] body = getResponseBody (response );
178
219
Charset charset = getCharset (response );
179
- String message = getErrorMessage (statusCode .value (), statusText , body , charset );
220
+ String message = getErrorMessage (statusCode .value (), statusText , body , charset , url , method );
180
221
181
222
RestClientResponseException ex ;
182
223
if (statusCode .is4xxClientError ()) {
0 commit comments