本文是精讲响应式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毫秒,也就是申请肯定会超时,肯定会抛出ConnectTimeoutExceptionTcpClient 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深入浅出系列》