作者:JackieTang

来源:生活点亮技术

1. 概览


在这个简短的教程中,将讨论如何实现一个自定义ResponseErrorHandler类并将其注入到RestTemplate实例中去,这样我们就可以在调用远程API时优雅地处理HTTP错误。


2. 默认的错误处理器

默认情况下,如果出现HTTP错误,RestTemplate将抛出下面所列的某一个异常:

  1. HttpClientErrorException –如果HTTP状态码为4 xx

  2. HttpServerErrorException –如果HTTP状态码为5xx

  3. UnknownHttpStatusCodeException –如果是一个未知的HTTP状态码

所有上面的异常类都继承了RestClientResponseException。

显然,添加自定义错误处理的最简单策略,是将调用逻辑嵌在try/catch块中。然后,我们根据需要,来处理捕获的异常。

但是,如果远程API的个数增加或单个API被多个地方调用,相应的try/catch块也会随之增加,即这个简单的策略并不具有很好的扩展性。如果我们所有的远程调用都复用一个错误处理器,那就会更高效。

3. 实现一个自定义ResponseErrorHandler

根据上面的需求,我们下面要实现的自定义ResponseErrorHandler,应该能够从响应中读取HTTP状态,并且:

  1. 抛出一个对我们的应用程序有意义的异常

  2. 简单处理,即直接忽略HTTP状态码,并让响应流连续不中断

并且,实现ResponseErrorHandler接口的自定义处理器需要注入到RestTemplate实例中。 具体而言,我们需要使用RestTemplateBuilder来构建RestTemplate,并在响应流中替换DefaultResponseErrorHandler。

那么,让我们先来创建一个自定义处理器RestTemplateResponseErrorHandler吧:

  1. @Component

  2. public class RestTemplateResponseErrorHandler

  3.  implements ResponseErrorHandler {

  4.    @Override

  5.    public boolean hasError(ClientHttpResponse httpResponse)

  6.      throws IOException {

  7.        return (

  8.          httpResponse.getStatusCode().series() == CLIENT_ERROR

  9.          || httpResponse.getStatusCode().series() == SERVER_ERROR);

  10.    }

  11.    @Override

  12.    public void handleError(ClientHttpResponse httpResponse)

  13.      throws IOException {

  14.        if (httpResponse.getStatusCode()

  15.          .series() == HttpStatus.Series.SERVER_ERROR) {

  16.            // handle SERVER_ERROR

  17.        } else if (httpResponse.getStatusCode()

  18.          .series() == HttpStatus.Series.CLIENT_ERROR) {

  19.            // handle CLIENT_ERROR

  20.            if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) {

  21.                throw new NotFoundException();

  22.            }

  23.        }

  24.    }

  25. }

接下来,我们使用RestTemplateBuilder来初始化RestTemplate实例,这样就可以加载前面创建的RestTemplateResponseErrorHandler类:

  1. @Service

  2. public class BarConsumerService {

  3.    private RestTemplate restTemplate;

  4.    @Autowired

  5.    public BarConsumerService(RestTemplateBuilder restTemplateBuilder) {

  6.        RestTemplate restTemplate = restTemplateBuilder

  7.          .errorHandler(new RestTemplateResponseErrorHandler())

  8.          .build();

  9.    }

  10.    public Bar fetchBarById(String barId) {

  11.        return restTemplate.getForObject("/bars/4242", Bar.class);

  12.    }

  13. }

4. 测试处理器

最后,让我们通过mock一个服务器,并让服务器返回一个NOT_FOUND HTTP状态码来测试这个自定义处理器:

  1. @RunWith(SpringRunner.class)

  2. @ContextConfiguration(classes = { NotFoundException.class, Bar.class })

  3. @RestClientTest

  4. public class RestTemplateResponseErrorHandlerIntegrationTest {

  5.    @Autowired

  6.    private MockRestServiceServer server;

  7.    @Autowired

  8.    private RestTemplateBuilder builder;

  9.    @Test(expected = NotFoundException.class)

  10.    public void  givenRemoteApiCall_when404Error_thenThrowNotFound() {

  11.        Assert.assertNotNull(this.builder);

  12.        Assert.assertNotNull(this.server);

  13.        RestTemplate restTemplate = this.builder

  14.          .errorHandler(new RestTemplateResponseErrorHandler())

  15.          .build();

  16.        this.server

  17.          .expect(ExpectedCount.once(), requestTo("/bars/4242"))

  18.          .andExpect(method(HttpMethod.GET))

  19.          .andRespond(withStatus(HttpStatus.NOT_FOUND));

  20.        Bar response = restTemplate

  21.          .getForObject("/bars/4242", Bar.class);

  22.        this.server.verify();

  23.    }

  24. }

5. 总结

本文提供了一个解决方案,用于实现和测试RestTemplate的自定义错误处理器,该处理器可以将HTTP错误转换为有意义的异常。

与往常一样,本文中提供的代码可以在Github上找到。

原文链接:https://www.baeldung.com/spring-rest-template-error-handling

作者: baeldung

译者:helloworldtang

-END-

 近期热文:

  • Swagger中配置了@ApiModelProperty的allowableValues属性但不显示的问题

  • 为什么Kafka中的分区数只能增加不能减少?

  • 一文带你吃透线程池

  • 设计一个百万级的消息推送系统

  • Hmily:高性能异步分布式事务TCC框架

  • 并行化:你的高并发大杀器

  • Spring Boot整合 Sentry 监控项目日志

  • 重磅:Elasticsearch上市!市值近50亿美元

  • 利用SPRING管理热加载的GROOVY对象!

  • Spring Boot中如何扩展XML请求和响应的支持

  • Java 11正式发布,新特性解读

关注我

点击“阅读原文”,看本号其他精彩内容

关注点分离之RestTemplate的错误处理相关推荐

  1. 社区首款 OAM 可视化平台发布!关注点分离、用户友好、上手难度低

    作者 | 徐运元,杭州谐云科技合伙人及资深架构师,云计算行业和 Kubernetes 生态资深从业者 **导读:**什么是 OAM?2019 年 10 月 17 日,阿里巴巴合伙人.阿里云智能基础产品 ...

  2. 应用题分析思路--关注点分离

    应用题分析思路–关注点分离 @(概率论) 在求解应用型概率题时,常常会因为模型尚未建立,关注点放在了概率求解上,二者交织在一起就很难厘清问题,因此拿出来强调一下. 一商店经销某种商品,每周进货量X与顾 ...

  3. 关注点分离与单一职责

    关注点分离(separation of concerns,SOC)是对只与"特定概念.目标"(关注点)相关联的软件组成部分进行"标识.封装和操纵"的能力,即标识 ...

  4. 【软件架构】4+2 Layered Architecture 4+2分层架构:软件架构中的关注点分离

    目录 4+2 Layered Architecture 4+2分层架构 Separation of Concerns Applied to Software Architecture软件架构中的关注点 ...

  5. 使用Consul做服务发现的若干姿势

    作者:波斯码 来源:http://blog.bossma.cn/consul/consul-service-register-and-discovery-style/?hmsr=toutiao.io& ...

  6. zookeeper-一个关于paxos的故事

    作者:大叔据 来源:大叔据 先讲一个故事. 从前,在国王Leslie Lamport的统治下,有个黑暗的希腊城邦叫paxos.城邦里有3类人, 决策者 提议者 群众 虽然这是一个黑暗的城邦但是很民主, ...

  7. 从面试官的角度谈谈大数据面试

    作者:大叔据 来源:大叔据 关于传授面试经验的文章太多了,眼花缭乱,我这里就不谈了,点进来想获取几吨面试学习资料的同学,抱歉让你失望了.(我是真的找不到那么多资料...).所以,今天我们只聊面试官. ...

  8. 为什么 Spring 框架如此流行?

    作者:shirehappy 来源:SpringForAll社区 想要学习更多关于Spring框架在Java开发者中如此流行?看这篇文章可以学到更多! 1.Spring框架特性 Spring是用于应用开 ...

  9. 如何健壮你的后端服务?

    作者: Ali猿来如此 来源:服务端思维 对每一个程序员而言,故障都是悬在头上的达摩克利斯之剑,都唯恐避之不及,如何避免故障是每一个程序员都在苦苦追寻希望解决的问题.对于这一问题,大家都可以从需求分析 ...

最新文章

  1. orm连接mysql_Django项目如何使用ORM连接MySQL
  2. 54. Leetcode 113. 路径总和 II (二叉树-二叉树路径和)
  3. 类与类之间关系,用C#和JavaScript体现
  4. 高射炮打蚊子,杀鸡用绝世好剑:在SAP Kyma上运行UI5应用
  5. centos一键清理磁盘空间_docker越来越大,心慌,清理一波吧
  6. PyTorch官方教程中文版:PYTORCH之60MIN入门教程代码学习
  7. python智能工厂_智能工厂关键技术应用 第八讲 智能工厂的Python编程应用
  8. ReentrantLock1.8源码
  9. Linux命令行学习日志-ps ax
  10. 如此轻松就能搭建聊天机器人,我也要弄一个~
  11. 机器学习入门-用Java实现简单感知机
  12. SpringBoot使用Ehcache
  13. android音频系统(4):AudioService之音量管理
  14. 华为ENSP之出口网关设备故障vrrp快速切换
  15. getPhoneNumber:fail Error: 用户绑定的手机需要进行验证,请在客户端完成短信验证
  16. chrome 插件 click 无效
  17. 一个Flash开发者从入门到放弃的成长之路
  18. 系统运维工程师装逼完全指南
  19. python文件路径path
  20. java学习之路8——Java集合框架

热门文章

  1. c/c++ ide 简介
  2. linux redis WARNING overcommit_memory is set to 0! 解决方案
  3. linux 内核 链表 list_head 使用方法
  4. pow函数gcc编译提示 undefined reference to `power' 的解决办法
  5. nginx+lua 配置302 不改写白名单哈希表
  6. C语言中, include 和 include 的区别和注意点
  7. html 表单自动数值,web前端学习技术之对HTML5 智能表单的理解
  8. java ee中javamail注解_JavaEE之注解
  9. mysql bigint 运算_mysql中int、bigint、smallint 和 tinyint的区别详细介绍
  10. 关不关机 扫地机器人_BOBOT扫地机器人能扫还能拖,你的家庭好助理