1313 */
1414package feign ;
1515
16+ import java .io .ByteArrayInputStream ;
17+ import java .io .IOException ;
18+ import java .io .InputStreamReader ;
19+ import java .io .Reader ;
20+ import java .nio .Buffer ;
21+ import java .nio .CharBuffer ;
22+ import java .nio .charset .Charset ;
23+ import java .util .Collection ;
24+ import java .util .Map ;
25+ import java .util .regex .Matcher ;
26+ import java .util .regex .Pattern ;
1627import static feign .Util .UTF_8 ;
1728import static feign .Util .checkNotNull ;
1829import static java .lang .String .format ;
19- import java .io .IOException ;
2030
2131/**
2232 * Origin exception type for all Http Apis.
@@ -121,7 +131,6 @@ static FeignException errorReading(Request request, Response response, IOExcepti
121131 }
122132
123133 public static FeignException errorStatus (String methodKey , Response response ) {
124- String message = format ("status %s reading %s" , response .status (), methodKey );
125134
126135 byte [] body = {};
127136 try {
@@ -131,6 +140,11 @@ public static FeignException errorStatus(String methodKey, Response response) {
131140 } catch (IOException ignored ) { // NOPMD
132141 }
133142
143+ String message = new FeignExceptionMessageBuilder ()
144+ .withResponse (response )
145+ .withMethodKey (methodKey )
146+ .withBody (body ).build ();
147+
134148 return errorStatus (response .status (), message , response .request (), body );
135149 }
136150
@@ -222,105 +236,215 @@ public FeignClientException(int status, String message, Request request, byte[]
222236 }
223237 }
224238
239+
225240 public static class BadRequest extends FeignClientException {
226241 public BadRequest (String message , Request request , byte [] body ) {
227242 super (400 , message , request , body );
228243 }
229244 }
230245
246+
231247 public static class Unauthorized extends FeignClientException {
232248 public Unauthorized (String message , Request request , byte [] body ) {
233249 super (401 , message , request , body );
234250 }
235251 }
236252
253+
237254 public static class Forbidden extends FeignClientException {
238255 public Forbidden (String message , Request request , byte [] body ) {
239256 super (403 , message , request , body );
240257 }
241258 }
242259
260+
243261 public static class NotFound extends FeignClientException {
244262 public NotFound (String message , Request request , byte [] body ) {
245263 super (404 , message , request , body );
246264 }
247265 }
248266
267+
249268 public static class MethodNotAllowed extends FeignClientException {
250269 public MethodNotAllowed (String message , Request request , byte [] body ) {
251270 super (405 , message , request , body );
252271 }
253272 }
254273
274+
255275 public static class NotAcceptable extends FeignClientException {
256276 public NotAcceptable (String message , Request request , byte [] body ) {
257277 super (406 , message , request , body );
258278 }
259279 }
260280
281+
261282 public static class Conflict extends FeignClientException {
262283 public Conflict (String message , Request request , byte [] body ) {
263284 super (409 , message , request , body );
264285 }
265286 }
266287
288+
267289 public static class Gone extends FeignClientException {
268290 public Gone (String message , Request request , byte [] body ) {
269291 super (410 , message , request , body );
270292 }
271293 }
272294
295+
273296 public static class UnsupportedMediaType extends FeignClientException {
274297 public UnsupportedMediaType (String message , Request request , byte [] body ) {
275298 super (415 , message , request , body );
276299 }
277300 }
278301
302+
279303 public static class TooManyRequests extends FeignClientException {
280304 public TooManyRequests (String message , Request request , byte [] body ) {
281305 super (429 , message , request , body );
282306 }
283307 }
284308
309+
285310 public static class UnprocessableEntity extends FeignClientException {
286311 public UnprocessableEntity (String message , Request request , byte [] body ) {
287312 super (422 , message , request , body );
288313 }
289314 }
290315
316+
291317 public static class FeignServerException extends FeignException {
292318 public FeignServerException (int status , String message , Request request , byte [] body ) {
293319 super (status , message , request , body );
294320 }
295321 }
296322
323+
297324 public static class InternalServerError extends FeignServerException {
298325 public InternalServerError (String message , Request request , byte [] body ) {
299326 super (500 , message , request , body );
300327 }
301328 }
302329
330+
303331 public static class NotImplemented extends FeignServerException {
304332 public NotImplemented (String message , Request request , byte [] body ) {
305333 super (501 , message , request , body );
306334 }
307335 }
308336
337+
309338 public static class BadGateway extends FeignServerException {
310339 public BadGateway (String message , Request request , byte [] body ) {
311340 super (502 , message , request , body );
312341 }
313342 }
314343
344+
315345 public static class ServiceUnavailable extends FeignServerException {
316346 public ServiceUnavailable (String message , Request request , byte [] body ) {
317347 super (503 , message , request , body );
318348 }
319349 }
320350
351+
321352 public static class GatewayTimeout extends FeignServerException {
322353 public GatewayTimeout (String message , Request request , byte [] body ) {
323354 super (504 , message , request , body );
324355 }
325356 }
357+
358+
359+ private static class FeignExceptionMessageBuilder {
360+
361+ private static final int MAX_BODY_BYTES_LENGTH = 400 ;
362+ private static final int MAX_BODY_CHARS_LENGTH = 200 ;
363+
364+ private Response response ;
365+
366+ private byte [] body ;
367+ private String methodKey ;
368+
369+ public FeignExceptionMessageBuilder withResponse (Response response ) {
370+ this .response = response ;
371+ return this ;
372+ }
373+
374+ public FeignExceptionMessageBuilder withBody (byte [] body ) {
375+ this .body = body ;
376+ return this ;
377+ }
378+
379+ public FeignExceptionMessageBuilder withMethodKey (String methodKey ) {
380+ this .methodKey = methodKey ;
381+ return this ;
382+ }
383+
384+ public String build () {
385+ StringBuilder result = new StringBuilder ();
386+
387+ if (response .reason () != null ) {
388+ result .append (format ("[%d %s]" , response .status (), response .reason ()));
389+ } else {
390+ result .append (format ("[%d]" , response .status ()));
391+ }
392+ result .append (format (" during [%s] to [%s] [%s]" , response .request ().httpMethod (),
393+ response .request ().url (), methodKey ));
394+
395+ result .append (format (": [%s]" , getBodyAsString (body , response .headers ())));
396+
397+ return result .toString ();
398+ }
399+
400+ private static String getBodyAsString (byte [] body , Map <String , Collection <String >> headers ) {
401+ Charset charset = getResponseCharset (headers );
402+ if (charset == null ) {
403+ charset = Util .UTF_8 ;
404+ }
405+ return getResponseBody (body , charset );
406+ }
407+
408+ private static String getResponseBody (byte [] body , Charset charset ) {
409+ if (body .length < MAX_BODY_BYTES_LENGTH ) {
410+ return new String (body , charset );
411+ }
412+ return getResponseBodyPreview (body , charset );
413+ }
414+
415+ private static String getResponseBodyPreview (byte [] body , Charset charset ) {
416+ try {
417+ Reader reader = new InputStreamReader (new ByteArrayInputStream (body ), charset );
418+ CharBuffer result = CharBuffer .allocate (MAX_BODY_CHARS_LENGTH );
419+
420+ reader .read (result );
421+ reader .close ();
422+ ((Buffer ) result ).flip ();
423+ return result .toString () + "... (" + body .length + " bytes)" ;
424+ } catch (IOException e ) {
425+ return e .toString () + ", failed to parse response" ;
426+ }
427+ }
428+
429+ private static Charset getResponseCharset (Map <String , Collection <String >> headers ) {
430+
431+ Collection <String > strings = headers .get ("content-type" );
432+ if (strings == null || strings .size () == 0 ) {
433+ return null ;
434+ }
435+
436+ Pattern pattern = Pattern .compile ("charset=([^\\ s])" );
437+ Matcher matcher = pattern .matcher (strings .iterator ().next ());
438+ if (!matcher .lookingAt ()) {
439+ return null ;
440+ }
441+
442+ String group = matcher .group (1 );
443+ if (!Charset .isSupported (group )) {
444+ return null ;
445+ }
446+ return Charset .forName (group );
447+
448+ }
449+ }
326450}
0 commit comments