精讲响应式WebClient第6篇-请求失败自动重试机制,强烈建议你看一看

本文是精讲响应式WebClient第6篇,前篇的blog访问地址如下:
- 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法
- 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解
- 精讲响应式WebClient第3篇-POST、DELETE、PUT方法使用
- 精讲响应式WebClient第4篇-文件上传与下载
- 精讲响应式WebClient第5篇-请求超时设置与异常处理
在上一篇我们为大家介绍了WebClient的异常处理方法,我们可以对指定的异常进行处理,也可以分类处理400-499、500-599状态码的HTTP异常。
我们本节为大家介绍的实际上是另外一种异常处理机制:请求失败之后自动重试。当WebClient发起请求,没有得到正常的响应结果,它就会每隔一段时间再次发送请求,可以发送n次,这个n是我们自定义的。n次请求都失败了,最后再将异常抛出,可以通过我们上一节交给大家的方法进行异常处理。也就是针对连接超时异常、读写超时异常等,或者是HTTP响应结果为非正常状态码(不是200状态码段),都在自动重试机制的范畴内。
如果您觉得我的文章对您有帮助的话,请帮忙点赞或分享,您的支持是我不竭的创作动力!
一、请求异常重试
下面的代码是请求"http://jsonplaceholder.typicode.com" 网站的服务,该网站是一个免费提供HTTP请求测试的服务端网站,我们可以用它测试WebClient。需要注意的是:正常的GET方法请求地址是"/posts/1",我特意的把它写错成为"/postss/1",这样可以触发404资源无法找到的异常。
public class ReTryTest {
@Test
public void testRetry() {
WebClient webClient = WebClient.builder()
.baseUrl("http://jsonplaceholder.typicode.com")
.build();
Mono<String> mono = webClient
.get() //GET 请求
.uri("/postss/1") // 请求路径,注意为了制造异常,这里是错的
.retrieve() //获取请求结果
.bodyToMono(String.class) //用Mono接收单个非集合对象数据
.doOnError(Exception.class, err -> { //处理异常
System.out.println(LocalDateTime.now() + "---发生错误:" +err.getMessage() );
})
.retry(3);
System.out.println("=====" + mono.block());
}
}
- doOnError异常处理是我们在上一节文章中为大家介绍的异常处理函数,我们在这里打印日志,观察重试次数
- retry(3)就是重点了,表示请求失败之后重试3次请求。也可以使用retry()无参方法,不设置次数,可以无限重试。这样显然不好,我们一般不用。
下面是doOnError中打印的控制台输出内容,一共打印了4次。(一次失败 + 三次重试失败)

二、重试时间间隔设置
上面的请求重试方法,请求失败之后立即重试,在很短的时间内就完成了3次重试。如果这是在生产环境下,可能你的服务端因为资源紧张造成请求响应超时等异常,这种重试机制无疑会让本就不堪重负的服务端雪上加霜。我们下面交给大家一种为重试设置时间间隔的方法:
.retryBackoff(3, Duration.ofSeconds(5));
- 第一个参数仍然表示重试3次
- 第二个参数表示按指数增长的时间间隔重试,第一次重试间隔5秒,第二次间隔10秒(5 x2),第三次间隔20秒(5x2x2)
源码如下:

三、retryWhen方法
上面的retryBackoff方法虽然已经一定程度上缓解了请求重试导致的服务端的压力,但是它还是不分场景的不断重试。
- 在实际的开发中,可以请求重试的场景应该是:网络异常、请求超时异常、服务端突然面临高并发导致的临时处理能力不足导致的超时等这种由于外部原因导致的异常场景。
- 对于那些由于程序员编写的bug、资源访问权限不足、资源找不到、HTTP版本不受支持等造成的异常,重试一万次也不会成功,反而可能因为你不断的重试造成服务器崩溃。
所以说Webclient已经在源码中,将retryBackoff()标记为废弃,建议使用retryWhen()代替它。retryWhen()可以指定针对某些异常进行重试,其他异常不做重试。

为了使用retryWhen(),需要引入下面的包
<dependency>
<groupId>io.projectreactor.addons</groupId>
<artifactId>reactor-extra</artifactId>
</dependency>
3.1.人为制造超时异常-用于测试
为了能够制造请求超时的异常场景,我们给连接超时设置为5毫秒,即:让所有请求一定会超时。(没有任何请求能在5毫秒内完成网络连接)
//认为设置请求超时时间为5毫秒,也就是请求一定会超时,一定会抛出ConnectTimeoutException
TcpClient tcpClient = TcpClient
.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5); //5毫秒
WebClient webClient = WebClient.builder()
.baseUrl("http://jsonplaceholder.typicode.com")
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
.build();
3.2.测试retryWhen
用Retry对象定义请求重试的条件,也就是retryWhen的when
Retry<?> retry = Retry.onlyIf(x -> x.exception() instanceof ConnectTimeoutException)
.retryMax(3) // 重试3次
.backoff(Backoff.exponential(Duration.ofSeconds(5),Duration.ofSeconds(60),2,true));
Mono<String> mono = webClient
.get() //GET 请求
.uri("/posts/1") // 请求路径,这里的请求路径是正确的
.retrieve()
.bodyToMono(String.class)
.retryWhen(retry); //满足Retry条件进行重试
System.out.println("=====" + mono.block());
Retry.onlyIf(x -> x.exception() instanceof ConnectTimeoutException)表示只有针对ConnectTimeoutException连接超市异常才进行请求重试,这里使用了java8的Predicate语法- Backoff.exponential表示按指数增长的时间间隔进行重试,可以自己指定指数重试因子,即指数的计数。这里我们仍然使用2作为指数重试因子,第一次重试间隔5秒,第二次间隔10秒(5 x2),第三次间隔20秒(5x2x2)
- 为防止间隔时间指数级无限延长,Backoff.exponential最长的重试间隔不能超过60秒,第二个参数。
- retryWhen(retry) 满足retry条件进行重试
3.3.retryWhen的其他方法

- onlyIf()表示捕获到指定的某个异常,进行请求重试
- allBut()表示除了某个异常之外,其他的异常被捕获则进行请求重试
- any() 表示针对所有异常,进行请求重试
- anyOf()表示指定某些异常类型,进行请求重试

backOff表示重试的时间间隔
- exponential()指数级增长的时间间隔
- fix()表示固定的时间间隔
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
精讲响应式WebClient第6篇-请求失败自动重试机制,强烈建议你看一看的更多相关文章
- 精讲响应式WebClient第5篇-请求超时设置与异常处理
本文是精讲响应式WebClient第5篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方 ...
- 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法
笔者在之前已经写了一系列的关于RestTemplate的文章,如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层HT ...
- 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解
本文是精讲响应式WebClient第2篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 在上一篇文章为大家介绍了响应式IO模型和WebClient的基本 ...
- 精讲响应式WebClient第3篇-POST、DELETE、PUT方法使用
本文是精讲响应式WebClient第3篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方 ...
- 精讲响应式WebClient第4篇-文件上传与下载
本文是精讲响应式WebClient第4篇,前篇的blog访问地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与基础用法 精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方 ...
- 精讲RestTemplate第8篇-请求失败自动重试机制
本文是精讲RestTemplate第8篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...
- 精讲RestTemplate第9篇-如何通过HTTP Basic Auth认证
本文是精讲RestTemplate第9篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...
- 精讲RestTemplate第10篇-使用代理作为跳板发送请求
本文是精讲RestTemplate第10篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层 ...
- 小书MybatisPlus第7篇-代码生成器的原理精讲及使用方法
本文是本系列文章的第七篇,前6篇访问地址如下: 小书MybatisPlus第1篇-整合SpringBoot快速开始增删改查 小书MybatisPlus第2篇-条件构造器的应用及总结 小书Mybatis ...
随机推荐
- 你一个 F12 能秒我?
参考文章 思路决定成败:F12给了我黑色的眼睛我却用它来挖洞 前言 了解大佬的思路才知道自己现在学的到底有多浅. 还没有到点,我就已经进入状态了,生而为人,我很抱歉. F12 的骚操作 Element ...
- PHP decbin() 函数
实例 把十进制转换为二进制: <?phpecho decbin("3") . "<br>";echo decbin("1" ...
- 职场老鸟,一文教你如何正确入门Python爬虫!
爬虫现在的火热程度我就不说了,先说一下这门技术能干什么事儿,主要为以下三方面: 1.爬取数据,进行市场调研和商业分析 爬取知乎.豆瓣等网站的优质话题内容:抓取房产网站买卖信息,分析房价变化趋势.做不同 ...
- c++中包含string成员的结构体拷贝导致的double free问题
最近调试代码遇到一个的问题,提示double free,但是找了好久也没有找到释放两次的地方,后来调试发现,是由于使用了一个包含string成员的结构体,这个结构体使用memcpy拷贝导致的问题: 代 ...
- jenkins集成spring boot持续化构建代码
我个人使用的是阿里云的云服务器,项目采用的是spring boot为框架,现在要做的功能就是将本地开发的代码提交到github中,通过jenkins自动化集成部署到云服务器.接下来开始步骤. 1 首先 ...
- Java Filter过滤器(拦截路径的配置+拦截方式的配置+生命周期+多个过滤器的先后执行顺序)
Java Filter过滤器+Listen监听器 啥是过滤器 顾名思义即过滤掉一些东西,比如我们经历的高考中考都是过滤器,他过滤掉一些在学习这一方面不是很好的人,而那些成绩好的人则升入高中,大学. 但 ...
- java方法中参数传递与随机点名器、库存管理案例
一 参数传递 1.定义: 参数传递,可以理解当我们要调用一个方法时,我们会把指定的数值,传递给方法中的参数, 这样方法中的参数就拥有了这个指定的值,可以使用该值,在方法中运算了.这种传递方式,我 们称 ...
- 高级搜索树-红黑树(RBTree)解析
目录 红黑树的定义 节点与树的定义 旋转操作 插入操作 情况1:p的兄弟u为黑色 情况2: p的兄弟u为红色 插入操作性能分析 代码实现 删除操作 情况1:x的接替者succ为红色 情况2:x的接替者 ...
- C#LeetCode刷题之#541-反转字符串 II(Reverse String II)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3951 访问. 给定一个字符串和一个整数 k,你需要对从字符串开头 ...
- 支持向量机SVM介绍
SVM为了达到更好的泛化效果,会构建具有"max-margin"的分类器(如下图所示),即最大化所有类里面距离超平面最近的点到超平面的距离,数学公式表示为$$\max\limits ...