结论:

resttemplate有默认的ErrorHandler,resttemplate发起http请求,一旦server抛异常,默认的只能打印status,无法打印message,自定义ErrorHandler,能打印status和message

server

@RestController
public class HelloController {@GetMapping("/hello")public String hello() {int i = 1 / 0;return "hello world";}
}

client

postman

用postman请求,返回如下,能解析异常信息,"message": "/ by zero",

restTemplate

但为啥restTemplate请求只能看到状态码,看不到详细信息呢,光看到500肯定是不够的,原因是resttemplate没有自定义ErrorHandler

2019-12-14 12:42:07.207 ERROR [hyg,,,] 10144 --- [           main] c.h.d.r.ResponseErrorHandlerTest         : 请求失败,url http://localhost:8000/helloorg.springframework.web.client.HttpServerErrorException$InternalServerError: 500 nullat org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:79) ~[spring-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]

restTemplate code

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ResponseErrorHandlerTest {@Autowiredprivate RestTemplate restTemplate;@Testpublic void responseErrorHandlerTest() {String url = "http://localhost:8000/hello";try {String hello = restTemplate.getForObject(url, String.class);assertThat(hello).contains(hello);} catch (Exception e) {log.error("请求失败,url {}", url, e);}}
}

自定义ErrorHandler能打印出来

自定义ErrorHandler,是不是能看到了

2019-12-14 12:50:20.302 ERROR [hyg,,,] 8044 --- [           main] c.h.d.r.ResponseErrorHandlerTest         : 请求HelloException失败,异常信息 {"timestamp":"2019-12-14 12:50:20","status":500,"error":"Internal Server Error","message":"/ by zero","path":"/hello"}
2019-12-14 12:50:20.318 ERROR [hyg,,,] 8044 --- [           main] c.h.d.r.ResponseErrorHandlerTest         : 请求失败,url http://localhost:8000/hellocom.hyg.demo.spring.resttemplate.HelloException: {"timestamp":"2019-12-14 12:50:20","status":500,"error":"Internal Server Error","message":"/ by zero","path":"/hello"}at com.hyg.demo.resttemplate.ResponseErrorHandlerTest.responseErrorHandlerTest(ResponseErrorHandlerTest.java:37) ~[test-classes/:na]

如何自定义resttemplate的ErrorHandler

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ResponseErrorHandlerTest {@Autowiredprivate RestTemplate restTemplate;@Testpublic void responseErrorHandlerTest() {this.restTemplate = new RestTemplate();restTemplate.setErrorHandler(responseErrorHandler(new HelloException()));String url = "http://localhost:8000/hello";try {String hello = restTemplate.getForObject(url, String.class);assertThat(hello).contains(hello);} catch (Exception e) {log.error("请求失败,url {}", url, e);}}private ResponseErrorHandler responseErrorHandler(HelloException helloException) {return new ResponseErrorHandler() {@Overridepublic boolean hasError(ClientHttpResponse response) throws IOException {return (response.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR ||response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR);}@Overridepublic void handleError(ClientHttpResponse response) throws IOException {String body = org.apache.commons.io.IOUtils.toString(response.getBody(), StandardCharsets.UTF_8);log.error("请求{}失败,异常信息 {}", helloException.getClass().getSimpleName(), body);try {helloException.setStatus(response.getStatusCode().value());helloException.setMessage(body);helloException.setServerSide(response.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR);helloException.setRetryAble(response.getStatusCode().series() != HttpStatus.Series.CLIENT_ERROR);throw helloException;} catch (Exception e) {helloException.setStatus(response.getStatusCode().value());helloException.setMessage(body);throw helloException;}}};}
}

服务端异常:一般以服务端名称+Exception命名

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
@Builder
public class HelloException extends RuntimeException{private int status; //http状态码private boolean isServerSide; //是不是server异常private boolean retryAble; // 是否重试,如果不是client_error就会重试private String code;private String message; //异常信息的bodyprivate Map<String,String> detail;
}

DefaultResponseErrorHandler

resttemplate的私有成员变量
private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();

DefaultResponseErrorHandlerd的handleError方法

 protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {String statusText = response.getStatusText();HttpHeaders headers = response.getHeaders();byte[] body = getResponseBody(response);Charset charset = getCharset(response);switch (statusCode.series()) {case CLIENT_ERROR:  throw HttpClientErrorException.create(statusCode, statusText, headers, body, charset);case SERVER_ERROR:  //body是详细信息,但没把body赋值给messagethrow HttpServerErrorException.create(statusCode, statusText, headers, body, charset);default:throw new UnknownHttpStatusCodeException(statusCode.value(), statusText, headers, body, charset);}}// 把statusCode.value() + " " + statusText当做maeeage,传给RestClientResponseExceptionorg.springframework.web.client.RestClientResponseException#RestClientResponseException
super(statusCode.value() + " " + statusText, statusCode.value(), statusText,responseHeaders, responseBody, responseCharset);public RestClientResponseException(String message, int statusCode, String statusText,@Nullable HttpHeaders responseHeaders, @Nullable byte[] responseBody, @Nullable Charset responseCharset) {super(message);this.rawStatusCode = statusCode;this.statusText = statusText;this.responseHeaders = responseHeaders;this.responseBody = (responseBody != null ? responseBody : new byte[0]);this.responseCharset = (responseCharset != null ? responseCharset.name() : null);}

自定义resttemplate的ErrorHandler相关推荐

  1. SpringBoot系列: RestTemplate 快速入门

    ==================================== 相关的文章 ==================================== SpringBoot系列: 与Sprin ...

  2. 关注点分离之RestTemplate的错误处理

    作者:JackieTang 来源:生活点亮技术 1. 概览 在这个简短的教程中,将讨论如何实现一个自定义ResponseErrorHandler类并将其注入到RestTemplate实例中去,这样我们 ...

  3. RestTemplate实践

    一.RestTemplate是什么 环境约束: spring-web-4.3.9.RELEASE Spring文档: https://docs.spring.io/spring/docs/4.3.9. ...

  4. 服务启动报错:Consider defining a bean of type ‘.RestTemplate‘ in your configuration

    Spring Boot <= 1.3 No need to define one, Spring Boot automatically defines one for you. (springb ...

  5. RestTemplate结合OkHttp3通用Rest Client客户端

    RestTemplate结合OkHttp3通用Rest Client客户端 文章目录 RestTemplate结合OkHttp3通用Rest Client客户端 一.OkHttp3 Authentic ...

  6. flask中的flask_uploads上传文件

    文章目录 1.测试结果: 2.主文件main.py: 3.显示错误页面404.html文件: 4.文件上传界面upload_Files.html: 1.测试结果: 如果上传的文件格式不符合要求的,则显 ...

  7. python中关于sqlite3数据库更新数据的使用

    1.文件结构: 其中html文件放置的文件名必须是templates,图片放置的文件名必须是static: 2.使用的数据库可视化工具DB Browser for sqlite下载: http://w ...

  8. python中关于sqlite3数据库删除数据的使用

    1.文件结构: 2.使用的数据库可视化工具DB Browser for sqlite下载: http://www.sqlitebrowser.org/ 3.使用DB Browser for sqlit ...

  9. python中使用html前端页面显示图像预测结果(改进)

    改进之处主要是代码,页面都没有发送改变: 现在使用文件类选择文件和上传文件: 以上框出来的地方就是改进之处: 1.训练的权重文件: 自己训练的权重文件,其中数据集来自身边收集,只训练的5个类别: 分别 ...

最新文章

  1. 整理对应_JSP第二版课后习题答案【侵权联系我删除】
  2. A Survey on Techniques in NLP--阅读笔记
  3. 【很详细】JDK安装与环境变量配置
  4. python中curve fit_在python中拟合多变量curve_fit
  5. ES6-2 块级作用域与嵌套、let、暂行性死区
  6. 解决: VUE 项目中表单提交中文乱码、接口请求参数中文乱码
  7. (推荐)jQuery性能优化指南
  8. input里面check 状态检测
  9. weight和weightSum的区别
  10. 解决IEM被禁用的问提
  11. 【关于PTA平台中出现的问题】warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
  12. php表格整体怎么移动,超级表格新版移动端操作指南
  13. linux中负载值为多少正常_Linux系统Load average负载详细解释
  14. python优惠券机器人_python实现机器人卡牌
  15. 妈蛋!! 居然是打广告的
  16. Eyenuk宣布FDA核准EyeArt自主AI系统用于糖尿病视网膜病变筛查
  17. selenium驱动Firefox安装和环境配置
  18. 一文读懂蒙特卡洛方法:谷歌围棋机器人科普
  19. 海思Hi3559AV100移植Qt5.9.1
  20. 从拼多多优惠券事件看到的一些反思

热门文章

  1. psid mysql_浅识MySQL
  2. 日语自学学习网站汇总
  3. 各种图片格式综述(转载)
  4. Python爬取新冠肺炎疫情实时数据(丁香园)
  5. 关系型数据库是什么?
  6. androidP Surface到SurfaceFlinger -->创建Surface (一)
  7. git设置用户名和邮箱地址
  8. WBS 及 WBS字典
  9. TigerGraph首将模式匹配与高效图计算相结合,为欺诈检测、网络安全保护、人工智能等应用增砖加瓦!
  10. 单元测试是什么?为什么要做单元测试?