spring Rest模板自定义异常处理
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21429899/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rest Template custom exception handling
提问by jarandaf
I am using some REST endpoints from an external API and I am using the Rest Template interface for this purpose. I would like to be able to throw custom app exceptions when I receive certain HTTP status codes from these calls. In order to achieve it, I am implementing the ResponseErrorHandler interface as follows:
我正在使用来自外部 API 的一些 REST 端点,并且为此目的使用了 Rest Template 接口。当我从这些调用中收到某些 HTTP 状态代码时,我希望能够抛出自定义应用程序异常。为了实现它,我实现了 ResponseErrorHandler 接口如下:
public class MyCustomResponseErrorHandler implements ResponseErrorHandler {
private ResponseErrorHandler myErrorHandler = new DefaultResponseErrorHandler();
public boolean hasError(ClientHttpResponse response) throws IOException {
return myErrorHandler.hasError(response);
}
public void handleError(ClientHttpResponse response) throws IOException {
String body = IOUtils.toString(response.getBody());
MyCustomException exception = new MyCustomException(response.getStatusCode(), body, body);
throw exception;
}
}
public class MyCustomException extends IOException {
private HttpStatus statusCode;
private String body;
public MyCustomException(String msg) {
super(msg);
// TODO Auto-generated constructor stub
}
public MyCustomException(HttpStatus statusCode, String body, String msg) {
super(msg);
this.statusCode = statusCode;
this.body = body;
}
public HttpStatus getStatusCode() {
return statusCode;
}
public void setStatusCode(HttpStatus statusCode) {
this.statusCode = statusCode;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
Finally, this is the client code (irrelevant code omitted):
最后,这是客户端代码(省略了无关代码):
public LoginResponse doLogin(String email, String password) {
HttpEntity<?> requestEntity = new HttpEntity<Object>(crateBasicAuthHeaders(email,password));
try{
ResponseEntity<LoginResponse> responseEntity = restTemplate.exchange(myBaseURL + "/user/account/" + email, HttpMethod.GET, requestEntity, LoginResponse.class);
return responseEntity.getBody();
} catch (Exception e) {
//Custom error handler in action, here we're supposed to receive a MyCustomException
if (e instanceof MyCustomException){
MyCustomException exception = (MyCustomException) e;
logger.info("An error occurred while calling api/user/account API endpoint: " + e.getMessage());
} else {
logger.info("An error occurred while trying to parse Login Response JSON object");
}
}
return null;
}
My app context:
我的应用程序上下文:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:spring="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- Rest template (used in bridge communication) -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="errorHandler" ref="myCustomResponseErrorHandler"></property>
</bean>
<!-- Bridge service -->
<bean id="myBridgeService" class="a.b.c.d.service.impl.MyBridgeServiceImpl"/>
<!-- Bridge error handler -->
<bean id="myCustomResponseErrorHandler" class="a.b.c.d.service.handlers.MyCustomResponseErrorHandler"/>
</beans>
I suspect I am not correctly understanding the behaviour of this custom error handling. Every single rest template method might throw a RestClientException, which following the exception hierarchy, is a subclass of RuntimeException and not IOException, which is thrown in the custom response error handler, i.e.: I can't catch my custom exception in the rest template method calls.
我怀疑我没有正确理解这个自定义错误处理的行为。每个单独的 rest 模板方法都可能抛出一个 RestClientException,它遵循异常层次结构,是 RuntimeException 的子类,而不是 IOException,它在自定义响应错误处理程序中抛出,即:我无法在 rest 模板方法中捕获我的自定义异常调用。
Any clues on how I could catch these exceptions? Spring RestTemplate invoking webservice with errors and analyze status codeis highly related but from my point of view experiences the same problem, although it was proposed as a solution.
关于如何捕捉这些异常的任何线索?Spring RestTemplate 调用有错误的 webservice 并分析状态代码是高度相关的,但从我的角度来看,遇到了同样的问题,尽管它是作为解决方案提出的。
[1]:
[1]:
回答by Sotirios Delimanolis
You've made your custom Exception
extend from IOException
您已将自定义Exception
扩展为IOException
public class MyCustomException extends IOException {
The ResponseErrorHandler#handleError()
method is invoked from RestTemplate#handleResponseError(..)
which is invoked by RestTemplate#doExecute(..)
. This root invocation is wrapped in a try-catch
block which catches IOException
and rethrows it wrapped in a ResourceAccessException
, which is a RestClientException
.
ResponseErrorHandler#handleError()
调用的方法从中RestTemplate#handleResponseError(..)
调用RestTemplate#doExecute(..)
。这个根调用被包裹在一个try-catch
块中,该块捕获IOException
并重新抛出包裹在 a 中的它ResourceAccessException
,它是 a RestClientException
。
One possibility is to catch the RestClientException
and get its cause
.
一种可能性是捕获RestClientException
并获取其cause
.
Another possibility is to make your custom Exception
be a sub type of RuntimeException
.
另一种可能性是使您的自定义Exception
成为RuntimeException
.
回答by Qy Zuo
You can create a controller using annotation @ControllerAdvice
if you using springmvc. In the controller write:
@ControllerAdvice
如果使用 springmvc,则可以使用注释创建控制器。在控制器中写:
@ExceptionHandler(HttpClientErrorException.class)
public String handleXXException(HttpClientErrorException e) {
log.error("log HttpClientErrorException: ", e);
return "HttpClientErrorException_message";
}
@ExceptionHandler(HttpServerErrorException.class)
public String handleXXException(HttpServerErrorException e) {
log.error("log HttpServerErrorException: ", e);
return "HttpServerErrorException_message";
}
...
// catch unknown error
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
log.error("log unknown error", e);
return "unknown_error_message";
}
and the DefaultResponseErrorHandler
throw these two kinds of exceptions:
并DefaultResponseErrorHandler
抛出这两种异常:
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = getHttpStatusCode(response);
switch (statusCode.series()) {
case CLIENT_ERROR:
throw new HttpClientErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
default:
throw new RestClientException("Unknown status code [" + statusCode + "]");
}
}
and you can get using:e.getResponseBodyAsString();
,e.getStatusCode();
blabla to get response message when the exceptions occurs.
并且您可以使用:e.getResponseBodyAsString();
,e.getStatusCode();
blabla 来获取异常发生时的响应消息。