提交 7f0e3481 编写于 作者: J jerzykrlk 提交者: Rossen Stoyanchev

Fine-grained RestTemplate exception hierarchy

Issue: SPR-15404
上级 2054fa21
......@@ -90,13 +90,77 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
switch (statusCode.series()) {
case CLIENT_ERROR:
handleClientError(response, statusCode);
return;
case SERVER_ERROR:
handleServerError(response, statusCode);
return;
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
}
}
private void handleClientError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
switch (statusCode) {
case BAD_REQUEST:
throw new HttpClientErrorException.BadRequest(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case UNAUTHORIZED:
throw new HttpClientErrorException.Unauthorized(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case FORBIDDEN:
throw new HttpClientErrorException.Forbidden(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case NOT_FOUND:
throw new HttpClientErrorException.NotFound(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case METHOD_NOT_ALLOWED:
throw new HttpClientErrorException.MethodNotAllowed(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case NOT_ACCEPTABLE:
throw new HttpClientErrorException.NotAcceptable(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case CONFLICT:
throw new HttpClientErrorException.Conflict(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case GONE:
throw new HttpClientErrorException.Gone(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case UNSUPPORTED_MEDIA_TYPE:
throw new HttpClientErrorException.UnsupportedMediaType(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case TOO_MANY_REQUESTS:
throw new HttpClientErrorException.TooManyRequests(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case UNPROCESSABLE_ENTITY:
throw new HttpClientErrorException.UnprocessableEntity(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
default:
throw new HttpClientErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, response.getStatusText(),
}
}
private void handleServerError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
switch (statusCode) {
case INTERNAL_SERVER_ERROR:
throw new HttpServerErrorException.InternalServerError(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case NOT_IMPLEMENTED:
throw new HttpServerErrorException.NotImplemented(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case BAD_GATEWAY:
throw new HttpServerErrorException.BadGateway(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case SERVICE_UNAVAILABLE:
throw new HttpServerErrorException.ServiceUnavailable(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case GATEWAY_TIMEOUT:
throw new HttpServerErrorException.GatewayTimeout(response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),
throw new HttpServerErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
}
}
......
......@@ -84,4 +84,255 @@ public class HttpServerErrorException extends HttpStatusCodeException {
super(statusCode, statusText, responseHeaders, responseBody, responseCharset);
}
/**
* Exception thrown when an HTTP 500 Internal Server Error is received.
*
* @since 5.1
* @see DefaultResponseErrorHandler
*/
public static class InternalServerError extends HttpServerErrorException {
private static final long serialVersionUID = -9078091996219553426L;
/**
* Construct a new instance of {@code HttpServerErrorException.InternalServerError}.
*/
public InternalServerError() {
super(HttpStatus.INTERNAL_SERVER_ERROR);
}
/**
* Construct a new instance of {@code HttpServerErrorException.InternalServerError} based on status text.
* @param statusText the status text
*/
public InternalServerError(String statusText) {
super(HttpStatus.INTERNAL_SERVER_ERROR, statusText);
}
/**
* Construct a new instance of {@code HttpServerErrorException.InternalServerError} based status text
* and response body content.
* @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 InternalServerError(String statusText, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.INTERNAL_SERVER_ERROR, statusText, responseBody, responseCharset);
}
/**
* Construct a new instance of {@code HttpServerErrorException.InternalServerError} based on status text
* and response body content.
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
*/
public InternalServerError(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.INTERNAL_SERVER_ERROR, statusText, responseHeaders, responseBody, responseCharset);
}
}
/**
* Exception thrown when an HTTP 501 Not Implemented is received.
*
* @since 5.1
* @see DefaultResponseErrorHandler
*/
public static class NotImplemented extends HttpServerErrorException {
private static final long serialVersionUID = -8858888941453536625L;
/**
* Construct a new instance of {@code HttpServerErrorException.NotImplemented}.
*/
public NotImplemented() {
super(HttpStatus.NOT_IMPLEMENTED);
}
/**
* Construct a new instance of {@code HttpServerErrorException.NotImplemented} based on status text.
* @param statusText the status text
*/
public NotImplemented(String statusText) {
super(HttpStatus.NOT_IMPLEMENTED, statusText);
}
/**
* Construct a new instance of {@code HttpServerErrorException.NotImplemented} based status text
* and response body content.
* @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 NotImplemented(String statusText, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.NOT_IMPLEMENTED, statusText, responseBody, responseCharset);
}
/**
* Construct a new instance of {@code HttpServerErrorException.NotImplemented} based on status text
* and response body content.
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
*/
public NotImplemented(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.NOT_IMPLEMENTED, statusText, responseHeaders, responseBody, responseCharset);
}
}
/**
* Exception thrown when an HTTP 502 Bad Gateway is received.
*
* @since 5.1
* @see DefaultResponseErrorHandler
*/
public static class BadGateway extends HttpServerErrorException {
private static final long serialVersionUID = -8989300848677585487L;
/**
* Construct a new instance of {@code HttpServerErrorException.BadGateway}.
*/
public BadGateway() {
super(HttpStatus.BAD_GATEWAY);
}
/**
* Construct a new instance of {@code HttpServerErrorException.BadGateway} based on status text.
* @param statusText the status text
*/
public BadGateway(String statusText) {
super(HttpStatus.BAD_GATEWAY, statusText);
}
/**
* Construct a new instance of {@code HttpServerErrorException.BadGateway} based status text
* and response body content.
* @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 BadGateway(String statusText, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.BAD_GATEWAY, statusText, responseBody, responseCharset);
}
/**
* Construct a new instance of {@code HttpServerErrorException.BadGateway} based on status text
* and response body content.
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
*/
public BadGateway(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.BAD_GATEWAY, statusText, responseHeaders, responseBody, responseCharset);
}
}
/**
* Exception thrown when an HTTP 503 Service Unavailable is received.
*
* @since 5.1
* @see DefaultResponseErrorHandler
*/
public static class ServiceUnavailable extends HttpServerErrorException {
private static final long serialVersionUID = 8777931838369402139L;
/**
* Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable}.
*/
public ServiceUnavailable() {
super(HttpStatus.SERVICE_UNAVAILABLE);
}
/**
* Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based on status text.
* @param statusText the status text
*/
public ServiceUnavailable(String statusText) {
super(HttpStatus.SERVICE_UNAVAILABLE, statusText);
}
/**
* Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based status text
* and response body content.
* @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 ServiceUnavailable(String statusText, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.SERVICE_UNAVAILABLE, statusText, responseBody, responseCharset);
}
/**
* Construct a new instance of {@code HttpServerErrorException.ServiceUnavailable} based on status text
* and response body content.
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
*/
public ServiceUnavailable(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.SERVICE_UNAVAILABLE, statusText, responseHeaders, responseBody, responseCharset);
}
}
/**
* Exception thrown when an HTTP 504 Gateway Timeout is received.
*
* @since 5.1
* @see DefaultResponseErrorHandler
*/
public static class GatewayTimeout extends HttpServerErrorException {
private static final long serialVersionUID = -7460116254256085095L;
/**
* Construct a new instance of {@code HttpServerErrorException.GatewayTimeout}.
*/
public GatewayTimeout() {
super(HttpStatus.GATEWAY_TIMEOUT);
}
/**
* Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based on status text.
* @param statusText the status text
*/
public GatewayTimeout(String statusText) {
super(HttpStatus.GATEWAY_TIMEOUT, statusText);
}
/**
* Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based status text
* and response body content.
* @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 GatewayTimeout(String statusText, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.GATEWAY_TIMEOUT, statusText, responseBody, responseCharset);
}
/**
* Construct a new instance of {@code HttpServerErrorException.GatewayTimeout} based on status text
* and response body content.
* @param statusText the status text
* @param responseHeaders the response headers (may be {@code null})
* @param responseBody the response body content (may be {@code null})
* @param responseCharset the response body charset (may be {@code null})
*/
public GatewayTimeout(String statusText, HttpHeaders responseHeaders, byte[] responseBody, Charset responseCharset) {
super(HttpStatus.GATEWAY_TIMEOUT, statusText, responseHeaders, responseBody, responseCharset);
}
}
}
......@@ -241,6 +241,9 @@ public class AbstractMockWebServerTestCase {
else if (request.getPath().equals("/status/notfound")) {
return new MockResponse().setResponseCode(404);
}
else if (request.getPath().equals("/status/badrequest")) {
return new MockResponse().setResponseCode(400);
}
else if (request.getPath().equals("/status/server")) {
return new MockResponse().setResponseCode(500);
}
......
package org.springframework.web.client;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import static org.mockito.Mockito.mock;
import static org.springframework.http.HttpStatus.*;
@RunWith(Parameterized.class)
public class DefaultReponseHanderSpecificErrorsTests {
@Parameters(name = "error: [{0}], exception: [{1}]")
public static Object[][] errorCodes() {
return new Object[][]{
// 4xx
{BAD_REQUEST, HttpClientErrorException.BadRequest.class},
{UNAUTHORIZED, HttpClientErrorException.Unauthorized.class},
{FORBIDDEN, HttpClientErrorException.Forbidden.class},
{NOT_FOUND, HttpClientErrorException.NotFound.class},
{METHOD_NOT_ALLOWED, HttpClientErrorException.MethodNotAllowed.class},
{NOT_ACCEPTABLE, HttpClientErrorException.NotAcceptable.class},
{CONFLICT, HttpClientErrorException.Conflict.class},
{TOO_MANY_REQUESTS, HttpClientErrorException.TooManyRequests.class},
{UNPROCESSABLE_ENTITY, HttpClientErrorException.UnprocessableEntity.class},
{I_AM_A_TEAPOT, HttpClientErrorException.class},
// 5xx
{INTERNAL_SERVER_ERROR, HttpServerErrorException.InternalServerError.class},
{NOT_IMPLEMENTED, HttpServerErrorException.NotImplemented.class},
{BAD_GATEWAY, HttpServerErrorException.BadGateway.class},
{SERVICE_UNAVAILABLE, HttpServerErrorException.ServiceUnavailable.class},
{GATEWAY_TIMEOUT, HttpServerErrorException.GatewayTimeout.class},
{HTTP_VERSION_NOT_SUPPORTED, HttpServerErrorException.class}
};
}
@Parameterized.Parameter
public HttpStatus httpStatus;
@Parameterized.Parameter(1)
public Class expectedExceptionClass;
private final DefaultResponseErrorHandler handler = new DefaultResponseErrorHandler();
private final ClientHttpResponse response = mock(ClientHttpResponse.class);
@Test
public void handleErrorIOException() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
given(response.getRawStatusCode()).willReturn(httpStatus.value());
given(response.getHeaders()).willReturn(headers);
try {
handler.handleError(response);
fail("expected " + expectedExceptionClass.getSimpleName());
}
catch (HttpStatusCodeException ex) {
assertEquals("Expected " + expectedExceptionClass.getSimpleName(), expectedExceptionClass, ex.getClass());
}
}
@Test
public void hasErrorTrue() throws Exception {
given(response.getRawStatusCode()).willReturn(HttpStatus.NOT_FOUND.value());
assertTrue(handler.hasError(response));
}
}
......@@ -180,6 +180,18 @@ public class RestTemplateIntegrationTests extends AbstractMockWebServerTestCase
}
}
@Test
public void badRequest() {
try {
template.execute(baseUrl + "/status/badrequest", HttpMethod.GET, null, null);
fail("HttpClientErrorException.BadRequest expected");
}
catch (HttpClientErrorException.BadRequest ex) {
assertEquals(HttpStatus.BAD_REQUEST, ex.getStatusCode());
assertEquals("400 Client Error", ex.getMessage());
}
}
@Test
public void serverError() {
try {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册