自定义 RestTemplate 异常处理 (转)
转自:https://ethendev.github.io/2018/11/06/RestTemplate-error-handler/
一些 API 的报错信息通过 Response 的 body返回。使用 HttpClient 能正常获取到 StatusCode 和 body 中的错误提示。然而使用 RestTemplate ,会直接抛出下面的异常。如果想获取原始的信息并进一步处理会比较麻烦。
org.springframework.web.client.HttpClientErrorException: 404 null
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:79)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:730)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:704)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:621)
RestTemplate 异常处理流程
下面看一下原因, RestTemplate 中的 getForObject, getForEntity 和 exchange 等常用方法最终都是调用 doExecute 方法。下面是 doExecute 方法源码
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations { private ResponseErrorHandler errorHandler;
...... @Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null; String resource;
try {
ClientHttpRequest request = this.createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
} response = request.execute();
// 处理 Response
this.handleResponse(url, method, response);
if (responseExtractor != null) {
Object var14 = responseExtractor.extractData(response);
return var14;
} resource = null;
} catch (IOException var12) {
resource = url.toString();
String query = url.getRawQuery();
resource = query != null ? resource.substring(0, resource.indexOf(63)) : resource;
throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
} finally {
if (response != null) {
response.close();
} } return resource;
} protected void handleResponse(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
ResponseErrorHandler errorHandler = this.getErrorHandler();
boolean hasError = errorHandler.hasError(response);
if (this.logger.isDebugEnabled()) {
try {
this.logger.debug(method.name() + " request for \"" + url + "\" resulted in " + response.getRawStatusCode() + " (" + response.getStatusText() + ")" + (hasError ? "; invoking error handler" : ""));
} catch (IOException var7) {
;
}
}
// 异常处理
if (hasError) {
errorHandler.handleError(url, method, response);
} }
}
从下面的代码可以看出,DefaultResponseErrorHandler 捕获并抛出了异常。
public class DefaultResponseErrorHandler implements ResponseErrorHandler {
... protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
switch(statusCode.series()) {
case CLIENT_ERROR:
throw new HttpClientErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(), response.getHeaders(), this.getResponseBody(response), this.getCharset(response));
}
}
}
如果想自己捕获异常信息,自己处理异常的话可以通过实现 ResponseErrorHandler 类来实现。其源码如下:
public interface ResponseErrorHandler { // 标示 Response 是否存在任何错误。实现类通常会检查 Response 的 HttpStatus。
boolean hasError(ClientHttpResponse var1) throws IOException; // 处理 Response 中的错误, 当 HasError 返回 true 时才调用此方法。
void handleError(ClientHttpResponse var1) throws IOException; // handleError 的替代方案,提供访问请求URL和HTTP方法的额外信息。
default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
this.handleError(response);
}
}
自定义 RestTemplate 异常处理
如果想像 HttpClient 一样直接从 Response 获取 HttpStatus 和 body 中的报错信息 而不抛出异常,可以通过下面的代码实现:
public class CustomErrorHandler implements ResponseErrorHandler { @Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return true;
} @Override
public void handleError(ClientHttpResponse response) throws IOException { }
}
设置 RestTemplate 的异常处理类
restTemplate.setErrorHandler(new CustomErrorHandler());
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, null, String.class);
System.out.println(response.getBody());
输出结果
{"code":404,"result":null,"message":"Resources not found"}
自定义 RestTemplate 异常处理 (转)的更多相关文章
- mvc自定义全局异常处理
异常信息处理是任何网站必不可少的一个环节,怎么有效显示,记录,传递异常信息又成为重中之重的问题.本篇将基于上篇介绍的html2cancas截图功能,实现mvc自定义全局异常处理.先看一下最终实现效果: ...
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- SpringBoot系列——自定义统一异常处理
前言 springboot内置的/error错误页面并不一定适用我们的项目,这时候就需要进行自定义统一异常处理,本文记录springboot进行自定义统一异常处理. 1.使用@ControllerAd ...
- Spring MVC自定义统一异常处理类,并且在控制台中输出错误日志
在使用SimpleMappingExceptionResolver实现统一异常处理后(参考Spring MVC的异常统一处理方法), 发现出现异常时,log4j无法在控制台输出错误日志.因此需要自定义 ...
- Laravel实践-自定义全局异常处理
在做API时,需要对一些异常进行全局处理 百牛信息技术bainiu.ltd整理发布于博客园比如添加用户执行失败时,需要返回错误信息 // 添加用户 $result = User::add($user) ...
- 精讲RestTemplate第7篇-自定义请求失败异常处理
本文是精讲RestTemplate第7篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...
- ASP.NET MVC自定义异常处理
1.自定义异常处理过滤器类文件 新建MyExceptionAttribute.cs异常处理类文件
- asp.net core 自定义异常处理中间件
asp.net core 自定义异常处理中间件 Intro 在 asp.net core 中全局异常处理,有时候可能不能满足我们的需要,可能就需要自己自定义一个中间件处理了,最近遇到一个问题,有一些异 ...
- SpringCloud微服务实战——搭建企业级开发框架(七):自定义通用响应消息及统一异常处理
平时开发过程中,无可避免我们需要处理各类异常,所以这里我们在公共模块中自定义统一异常,Spring Boot 提供 @RestControllerAdvice 注解统一异常处理,我们在GitEgg ...
随机推荐
- Log4j2日志框架集成Slf4j日志门面
1.说明 本文介绍使用日志门面Slf4j打印日志, 底层日志实现使用Log4j2框架, 方便以后切换底层日志实现, Log4j2可以替换成Logback等. 2.依赖管理 在pom.xml依赖管理中导 ...
- Hadoop集群安装(真分布式)
Hadoop真分布式完全集群安装,基于版本2.7.2安装, 在两台Linux机器上面分别安装Hadoop的master和slave节点. 1.安装说明 不管NameNode还是DataNode节点,安 ...
- pytest 一个测试类怎样使用多种fixture前置方法
fixture()方法写在哪里? @pytest.fixture(scope="范围")写在conftest文件中,如下图 怎么使用fixture()呢?分为一个类中使用一个前置或 ...
- 新装CentOS7用yum安装软件提示 cannot find a valid baseurl for repobase7x86_64
1.打开网络配置文件:vi /etc/sysconfig/network-scripts/ifcfg-ens33(每个机子都可能不一样,但格式会是"ifcfg-e..."). 2. ...
- 初识python: 自定义函数
什么是函数? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率. 函数的定义方法: def test(x): '函数定义方法' x+=1 r ...
- 在CentOS7 安装 jq
root@: 安装EPEL源: yum install epel-release 安装完EPEL源后,可以查看下jq包是否存在: yum list jq 安装jq: yum install jq 命令 ...
- Servlet初级学习加入数据库操作(二)
源代码地址:https://url56.ctfile.com/f/34653256-527822631-2e255a(访问密码:7567) 将页面中的数据逐步替换为数据库管理 准备一个连接数据库的类 ...
- python多环境管理一(venv与virtualenv)
一.背景 我们经常会遇见这样的场景: 1.各个项目使用的python版本不相同 由于Python的解释器版本众多,各版本之间差异非常大.特别是python2和python3,互不兼容. 有些项目可能用 ...
- Java反射详解:入门+使用+原理+应用场景
反射非常强大和有用,现在市面上绝大部分框架(spring.mybatis.rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用. 所以,在你Java进阶的道路上,你需要掌握好 ...
- JVM探究(一)谈谈双亲委派机制和沙箱安全机制
JVM探究 请你谈谈你对JVM的理解?java8虚拟机和之前的变化gengxin? 什么是OOM,什么是栈溢出StackOverFlowError JVM的常用调优参数有哪些? 内存快转如何抓取,怎么 ...