【问题标题】:Rest Template custom exception handlingRest Template 自定义异常处理
【发布时间】:2014-02-21 04:28:13
【问题描述】:

我正在使用来自外部 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;
    }

}

最后,这是客户端代码(无关代码省略):

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;
}

我的应用上下文:

<?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>

我怀疑我没有正确理解此自定义错误处理的行为。每个单独的 rest 模板方法都可能抛出一个 RestClientException,它遵循异常层次结构,是 RuntimeException 的子类,而不是在自定义响应错误处理程序中引发的 IOException,即:I can't catch my custom exception in the rest template method来电。

关于如何捕获这些异常的任何线索? Spring RestTemplate invoking webservice with errors and analyze status code 高度相关,但从我的角度来看,遇到了同样的问题,尽管它是作为解决方案提出的。

[1]:

【问题讨论】:

标签: spring spring-mvc


【解决方案1】:

您已将自定义 Exception 扩展自 IOException

public class MyCustomException extends IOException {

ResponseErrorHandler#handleError() 方法从RestTemplate#handleResponseError(..) 调用,RestTemplate#doExecute(..) 调用该方法。这个根调用被包裹在一个try-catch 块中,该块捕获IOException 并重新抛出它包裹在一个ResourceAccessException 中,这是一个RestClientException

一种可能性是捕获RestClientException 并获取它的cause

另一种可能性是让您的自定义Exception 成为RuntimeException 的子类型。

【讨论】:

  • 这里最好的方法是什么?如果我的 Exception 必须从 Exception 继承怎么办,我每次使用 RestTemplate 时都必须在 RestClientException 后面获取 Exception
  • @Zarathustra 我不认为你可以有另一种类型的检查异常。 handleError 仅被声明为抛出 IOException。除非您在谈论其他组件,否则只有这两个选项,IOException 或未经检查的异常。
【解决方案2】:

如果你使用 springmvc,你可以使用注解 @ControllerAdvice 创建一个控制器。在控制器中写:

@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";
}

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 + "]");
    }
}

当异常发生时,您可以使用:e.getResponseBodyAsString();e.getStatusCode();blabla 来获取响应消息。

【讨论】:

    猜你喜欢
    • 2013-07-02
    • 1970-01-01
    • 2013-03-14
    • 2017-11-28
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2015-07-01
    • 1970-01-01
    相关资源
    最近更新 更多