SpringBoot - 网络请求客户端WebClient使用详解7(超时时长、自动重试)
八、设置超时属性
(1)我们可以使用 timeout 方法设置一个超时时长。如果 HTTP 请求超时,便会发生 TimeoutException 异常。
@RestController public class HelloController { // 创建 WebClient 对象 private WebClient webClient = WebClient.builder() .baseUrl("http://localhost:8080") .build(); @GetMapping("/test") public String test() { Mono<String> mono = webClient .get() // GET 请求 .uri("/data") // 请求一个不存在的路径 .retrieve() // 获取响应体 .bodyToMono(String.class) .timeout(Duration.ofSeconds(3)); // 3秒超时 return mono.block(); } @GetMapping("/data") public String data() throws InterruptedException { //等待2分钟再返回 Thread.sleep(120 * 1000); return "hangge.com"; } }
(2)使用 Postman 发起请求结果如下:
九、请求异常自动重试
1,设置重试次数
(1)使用 retry() 方法可以设置当请求异常时的最大重试次数,如果不带参数则表示无限重试,直至成功。
@RestController public class HelloController { // 创建 WebClient 对象 private WebClient webClient = WebClient.builder() .baseUrl("http://localhost:8080") .build(); @GetMapping("/test") public String test() { Mono<String> mono = webClient .get() // GET 请求 .uri("/data") // 请求一个不存在的路径 .retrieve() // 获取响应体 .bodyToMono(String.class) .timeout(Duration.ofSeconds(3)) // 3秒超时 .retry(3); // 重试3次 return mono.block(); } @GetMapping("/data") public String data() throws InterruptedException { System.out.println("--- start ---"); //等待2分钟再返回 Thread.sleep(120 * 1000); return "hangge.com"; } }
(2)执行后控制台输出如下,可以看到最开始的 1 次请求加上 3 次重试,最终一共请求了 4 次。
2,设置重试时间间隔
(1)使用 retry 方法默认情况下请求失败后会立刻重新发起请求,如果希望在每次重试前加个时间间隔(等待),可以使用 retryBackoff 方法。
(2)下面代码同样是当发生请求失败后自动重试 3 次,只不过重试前会等待个 10 秒。
@RestController public class HelloController { // 创建 WebClient 对象 private WebClient webClient = WebClient.builder() .baseUrl("http://localhost:8080") .build(); @GetMapping("/test") public String test() { Mono<String> mono = webClient .get() // GET 请求 .uri("/data") // 请求一个不存在的路径 .retrieve() // 获取响应体 .bodyToMono(String.class) .timeout(Duration.ofSeconds(3)) // 3秒超时 .retryBackoff(3, Duration.ofSeconds(10)); // 重试3次,间隔10秒 return mono.block(); } @GetMapping("/data") public String data() throws InterruptedException { System.out.println("--- start ---"); //等待2分钟再返回 Thread.sleep(120 * 1000); return "hangge.com"; } }
3,指定需要重试的异常
(1)不管是前面的 retry 方法还是 retryBackoff 方法,设置后无论发生何种异常都会进行重试。如果需要更加精细的控制,比如指定的异常才需要重试,则可以使用 retryWhen 方法。
(2)在使用 retryWhen 方法之前,我们项目中还需要先引入 reactor-extra 包,因为需要用到里面的 Retry 类。
<dependency> <groupId>io.projectreactor.addons</groupId> <artifactId>reactor-extra</artifactId> </dependency>
(3)下面样例只有发生 RuntimeException 异常时才会进行重试:
注意:如果还需要设置对应的重试次数和间隔时间,需要分别通过 Retry 的 retryMax 和 backoff 方法进行设置。
@RestController public class HelloController { // 创建 WebClient 对象 private WebClient webClient = WebClient.builder() .baseUrl("http://localhost:8080") .build(); @GetMapping("/test") public String test() { // 定义重试条件 Retry<?> retry = Retry.anyOf(RuntimeException.class) // 只有RuntimeException异常才重试 .retryMax(3) // 重试3次 .backoff(Backoff.fixed(Duration.ofSeconds(10))); // 每次重试间隔10秒 Mono<String> mono = webClient .get() // GET 请求 .uri("/data") // 请求一个不存在的路径 .retrieve() // 获取响应体 .bodyToMono(String.class) .timeout(Duration.ofSeconds(3)) // 3秒超时 .retryWhen(retry); return mono.block(); } @GetMapping("/data") public String data() { System.out.println("--- start ---"); throw new RuntimeException("发生错误"); } }
(4)下面样例除了 RuntimeException 异常外,发生其它一切异常都会进行重试:
@RestController public class HelloController { // 创建 WebClient 对象 private WebClient webClient = WebClient.builder() .baseUrl("http://localhost:8080") .build(); @GetMapping("/test") public String test() { // 定义重试条件 Retry<?> retry = Retry.allBut(RuntimeException.class) // 除了RuntimeException异常都重试 .retryMax(3) // 重试3次 .backoff(Backoff.fixed(Duration.ofSeconds(10))); // 每次重试间隔10秒 Mono<String> mono = webClient .get() // GET 请求 .uri("/data") // 请求一个不存在的路径 .retrieve() // 获取响应体 .bodyToMono(String.class) .timeout(Duration.ofSeconds(3)) // 3秒超时 .retryWhen(retry); return mono.block(); } @GetMapping("/data") public String data() { System.out.println("--- start ---"); throw new RuntimeException("发生错误"); } }