SPR-7591 - HttpStatusCodeException should contain response body
This commit is contained in:
parent
6e516b7281
commit
70cb81b4b5
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2010 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -17,9 +17,12 @@
|
||||||
package org.springframework.web.client;
|
package org.springframework.web.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the {@link ResponseErrorHandler} interface.
|
* Default implementation of the {@link ResponseErrorHandler} interface.
|
||||||
|
|
@ -64,14 +67,18 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
|
||||||
*/
|
*/
|
||||||
public void handleError(ClientHttpResponse response) throws IOException {
|
public void handleError(ClientHttpResponse response) throws IOException {
|
||||||
HttpStatus statusCode = response.getStatusCode();
|
HttpStatus statusCode = response.getStatusCode();
|
||||||
|
MediaType contentType = response.getHeaders().getContentType();
|
||||||
|
Charset charset = contentType != null ? contentType.getCharSet() : null;
|
||||||
|
byte[] body = FileCopyUtils.copyToByteArray(response.getBody());
|
||||||
switch (statusCode.series()) {
|
switch (statusCode.series()) {
|
||||||
case CLIENT_ERROR:
|
case CLIENT_ERROR:
|
||||||
throw new HttpClientErrorException(statusCode, response.getStatusText());
|
throw new HttpClientErrorException(statusCode, response.getStatusText(), body, charset);
|
||||||
case SERVER_ERROR:
|
case SERVER_ERROR:
|
||||||
throw new HttpServerErrorException(statusCode, response.getStatusText());
|
throw new HttpServerErrorException(statusCode, response.getStatusText(), body, charset);
|
||||||
default:
|
default:
|
||||||
throw new RestClientException("Unknown status code [" + statusCode + "]");
|
throw new RestClientException("Unknown status code [" + statusCode + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.web.client;
|
package org.springframework.web.client;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -44,4 +46,19 @@ public class HttpClientErrorException extends HttpStatusCodeException {
|
||||||
super(statusCode, statusText);
|
super(statusCode, statusText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance of {@code HttpClientErrorException} based on a {@link HttpStatus}, status text, and
|
||||||
|
* response body content.
|
||||||
|
*
|
||||||
|
* @param statusCode the status code
|
||||||
|
* @param statusText the status text
|
||||||
|
* @param responseBody the response body content, may be {@code null}
|
||||||
|
* @param responseCharset the response body charset, may be {@code null}
|
||||||
|
*/
|
||||||
|
public HttpClientErrorException(HttpStatus statusCode,
|
||||||
|
String statusText,
|
||||||
|
byte[] responseBody,
|
||||||
|
Charset responseCharset) {
|
||||||
|
super(statusCode, statusText, responseBody, responseCharset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.web.client;
|
package org.springframework.web.client;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception thrown when an HTTP 5xx is received.
|
* Exception thrown when an HTTP 5xx is received.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 3.0
|
|
||||||
* @see DefaultResponseErrorHandler
|
* @see DefaultResponseErrorHandler
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class HttpServerErrorException extends HttpStatusCodeException {
|
public class HttpServerErrorException extends HttpStatusCodeException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}.
|
* Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}.
|
||||||
|
*
|
||||||
* @param statusCode the status code
|
* @param statusCode the status code
|
||||||
*/
|
*/
|
||||||
public HttpServerErrorException(HttpStatus statusCode) {
|
public HttpServerErrorException(HttpStatus statusCode) {
|
||||||
|
|
@ -37,6 +40,7 @@ public class HttpServerErrorException extends HttpStatusCodeException {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus} and status text.
|
* Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus} and status text.
|
||||||
|
*
|
||||||
* @param statusCode the status code
|
* @param statusCode the status code
|
||||||
* @param statusText the status text
|
* @param statusText the status text
|
||||||
*/
|
*/
|
||||||
|
|
@ -44,4 +48,20 @@ public class HttpServerErrorException extends HttpStatusCodeException {
|
||||||
super(statusCode, statusText);
|
super(statusCode, statusText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance of {@code HttpServerErrorException} based on a {@link HttpStatus}, status text, and
|
||||||
|
* response body content.
|
||||||
|
*
|
||||||
|
* @param statusCode the status code
|
||||||
|
* @param statusText the status text
|
||||||
|
* @param responseBody the response body content, may be {@code null}
|
||||||
|
* @param responseCharset the response body charset, may be {@code null}
|
||||||
|
* @since 3.0.5
|
||||||
|
*/
|
||||||
|
public HttpServerErrorException(HttpStatus statusCode,
|
||||||
|
String statusText,
|
||||||
|
byte[] responseBody,
|
||||||
|
Charset responseCharset) {
|
||||||
|
super(statusCode, statusText, responseBody, responseCharset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2010 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.web.client;
|
package org.springframework.web.client;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,33 +29,56 @@ import org.springframework.http.HttpStatus;
|
||||||
*/
|
*/
|
||||||
public abstract class HttpStatusCodeException extends RestClientException {
|
public abstract class HttpStatusCodeException extends RestClientException {
|
||||||
|
|
||||||
|
private static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
|
||||||
|
|
||||||
private final HttpStatus statusCode;
|
private final HttpStatus statusCode;
|
||||||
|
|
||||||
private final String statusText;
|
private final String statusText;
|
||||||
|
|
||||||
|
private final byte[] responseBody;
|
||||||
|
|
||||||
|
private final Charset responseCharset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}.
|
* Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}.
|
||||||
|
*
|
||||||
* @param statusCode the status code
|
* @param statusCode the status code
|
||||||
*/
|
*/
|
||||||
protected HttpStatusCodeException(HttpStatus statusCode) {
|
protected HttpStatusCodeException(HttpStatus statusCode) {
|
||||||
super(statusCode.toString());
|
this(statusCode, statusCode.name(), null, null);
|
||||||
this.statusCode = statusCode;
|
|
||||||
this.statusText = statusCode.name();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus} and status text.
|
* Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus} and status text.
|
||||||
|
*
|
||||||
* @param statusCode the status code
|
* @param statusCode the status code
|
||||||
* @param statusText the status text
|
* @param statusText the status text
|
||||||
*/
|
*/
|
||||||
protected HttpStatusCodeException(HttpStatus statusCode, String statusText) {
|
protected HttpStatusCodeException(HttpStatus statusCode, String statusText) {
|
||||||
|
this(statusCode, statusText, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance of {@code HttpStatusCodeException} based on a {@link HttpStatus}, status text, and
|
||||||
|
* response body content.
|
||||||
|
*
|
||||||
|
* @param statusCode the status code
|
||||||
|
* @param statusText the status text
|
||||||
|
* @param responseBody the response body content, may be {@code null}
|
||||||
|
* @param responseCharset the response body charset, may be {@code null}
|
||||||
|
* @since 3.0.5
|
||||||
|
*/
|
||||||
|
protected HttpStatusCodeException(HttpStatus statusCode,
|
||||||
|
String statusText,
|
||||||
|
byte[] responseBody,
|
||||||
|
Charset responseCharset) {
|
||||||
super(statusCode.value() + " " + statusText);
|
super(statusCode.value() + " " + statusText);
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
this.statusText = statusText;
|
this.statusText = statusText;
|
||||||
|
this.responseBody = responseBody != null ? responseBody : new byte[0];
|
||||||
|
this.responseCharset = responseCharset != null ? responseCharset : DEFAULT_CHARSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HTTP status code.
|
* Returns the HTTP status code.
|
||||||
*/
|
*/
|
||||||
|
|
@ -67,4 +93,27 @@ public abstract class HttpStatusCodeException extends RestClientException {
|
||||||
return this.statusText;
|
return this.statusText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the response body as a byte array.
|
||||||
|
*
|
||||||
|
* @since 3.0.5
|
||||||
|
*/
|
||||||
|
public byte[] getResponseBodyAsByteArray() {
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the response body as a string.
|
||||||
|
*
|
||||||
|
* @since 3.0.5
|
||||||
|
*/
|
||||||
|
public String getResponseBodyAsString() {
|
||||||
|
try {
|
||||||
|
return new String(responseBody, responseCharset.name());
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException ex) {
|
||||||
|
// should not occur
|
||||||
|
throw new InternalError(ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,14 +145,30 @@ public class RestTemplateIntegrationTests {
|
||||||
assertEquals("Invalid content", helloWorld, s);
|
assertEquals("Invalid content", helloWorld, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = HttpClientErrorException.class)
|
@Test
|
||||||
public void notFound() {
|
public void notFound() {
|
||||||
template.execute(URI + "/errors/notfound", HttpMethod.GET, null, null);
|
try {
|
||||||
|
template.execute(URI + "/errors/notfound", HttpMethod.GET, null, null);
|
||||||
|
fail("HttpClientErrorException expected");
|
||||||
|
}
|
||||||
|
catch (HttpClientErrorException ex) {
|
||||||
|
assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode());
|
||||||
|
assertNotNull(ex.getStatusText());
|
||||||
|
assertNotNull(ex.getResponseBodyAsString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = HttpServerErrorException.class)
|
@Test
|
||||||
public void serverError() {
|
public void serverError() {
|
||||||
template.execute(URI + "/errors/server", HttpMethod.GET, null, null);
|
try {
|
||||||
|
template.execute(URI + "/errors/server", HttpMethod.GET, null, null);
|
||||||
|
fail("HttpServerErrorException expected");
|
||||||
|
}
|
||||||
|
catch (HttpServerErrorException ex) {
|
||||||
|
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatusCode());
|
||||||
|
assertNotNull(ex.getStatusText());
|
||||||
|
assertNotNull(ex.getResponseBodyAsString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue