Spring Boot 如何处理客户端中的RestTemplate异常?

sy5wg1nm  于 2023-04-20  发布在  Spring
关注(0)|答案(2)|浏览(287)

我有一个springboot应用程序,它调用我编写的客户端库,对第三方服务进行REST调用。
我希望能够捕获任何/所有可能来自这个客户端库的异常,并将它们Map到我自己的自定义异常,我可以在我的应用程序中捕获。
在客户端库中,我有一个RestTemplate bean,我已经将ErrorHandler绑定到它,如下所示:

public class CustomRestTemplateErrorHandler implements ResponseErrorHandler {

}

我使用'hasError'和'handleError'的典型方法。如果我返回一个HTTP 400,其中包含一些预期的错误响应主体,我可以捕获此错误并将其Map到我的异常,如下所示:

@Override
    public void handleError(ClientHttpResponse response) {
        try {
            if (!response.getStatusCode().is2xxSuccessful()) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(response.getBody()));
                String httpBodyResponse = reader.lines()
                        .collect(Collectors.joining(""));

                ObjectMapper mapper = new ObjectMapper();
                ExpectedErrorResponse errorResponse = mapper.readValue(httpBodyResponse, ExpectedErrorResponse.class);
                throw new CustomException(response.getStatusCode(), errorResponse);
            }
        } catch (IOException ioException) {
            throw new CustomException(ioException.getMessage(), ioException.getCause());
        }
    }

假设我运行这个测试,而下游服务器没有运行。我将得到以下Exception,其中没有被我的错误处理程序捕获Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://127.0.0.1:8082/": Connect to 127.0.0.1:8082 [/127.0.0.1] failed: Connection refused: connect; nested exception is org.apache.http.conn.HttpHostConnectException: Connect to 127.0.0.1:8082 [/127.0.0.1] failed: Connection refused: connect
如何在ResponseErrorHandler中捕获预期类型的错误响应和RestClientException?
谢谢

k4ymrczo

k4ymrczo1#

问题陈述

ResourceAccessException是一个例外class,它不是从IOException继承的,所以在这个特定的情况下,你的catch不会被输入。所以,你有几个选择:

捕获异常

验证码:

catch (Exception exception) {
    //your code
}

这将同时处理IOExceptionRestClientException。尽管这是一个简短且易于阅读的解决方案,但如果您可能需要以不同的方式捕获其他异常,那么您可能希望决定反对它。但在许多情况下,这可能会帮助您。最终,您需要决定是否要这样做。

捕获多个异常

密码

catch (IOException ioException) {
    // Your code
} catch (RestClientException restClientException) {
    // Your code
}

这正是你想做的,所以如果第一个建议没有帮助,这是一个有用的解决方案。

捕获同一块中的多个异常类型

密码

catch (IOException | RestClientException myException) {
    // Your code
}

这是将您想要处理的根异常类型列入白名单,这是解决问题的一种简洁方法。

j0pj023g

j0pj023g2#

您可以通过如下方式修改代码来捕获预期的错误响应和ResponseErrorHandler中的RestClientException
下面是一个例子:

public class CustomRestTemplateErrorHandler implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        // Implement your custom logic to determine if the response has an error
        // For example, you can check for non-2xx response status codes here
        return !response.getStatusCode().is2xxSuccessful();
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        try {
            if (hasError(response)) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(response.getBody()));
                String httpBodyResponse = reader.lines()
                        .collect(Collectors.joining(""));

                ObjectMapper mapper = new ObjectMapper();
                ExpectedErrorResponse errorResponse = mapper.readValue(httpBodyResponse, ExpectedErrorResponse.class);
                throw new CustomException(response.getStatusCode(), errorResponse);
            }
        } catch (IOException ioException) {
            // Catch and re-throw the expected error response
            throw new CustomException(ioException.getMessage(), ioException.getCause());
        } catch (RestClientException restClientException) {
            // Catch and handle the RestClientException
            throw new CustomException("Failed to make REST call", restClientException);
        }
    }
}

相关问题