为啥 WebFlux-WebClient 超时不起作用?
Posted
技术标签:
【中文标题】为啥 WebFlux-WebClient 超时不起作用?【英文标题】:Why WebFlux-WebClient Timeout not working?为什么 WebFlux-WebClient 超时不起作用? 【发布时间】:2021-07-07 02:07:26 【问题描述】:我正在使用 Spring boot Webflux 2.4.4(最新)并尝试使用 WebClient 调用后端 URL。 WebClient 总是在 20 秒以上响应。如果我直接点击 URL,它会在毫秒内响应。
Pom 如下所示:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
代码如下:
@RestController
public class Controller
@GetMapping("/test")
public Mono<String> test()
long startMillis = System.currentTimeMillis();
return webClient().get().uri("https://www.google.com").exchangeToMono(response ->
System.out.println("Elapsed Time is: " + (System.currentTimeMillis() - startMillis));
if (response.statusCode().equals(HttpStatus.OK))
return Mono.just("OK");
return Mono.just("OK");
);
private WebClient webClient()
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient
.create().secure().responseTimeout(Duration.ofMillis(1000))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000).doOnConnected(c -> c
.addHandlerLast(new ReadTimeoutHandler(3)).addHandlerLast(new WriteTimeoutHandler(3)))))
.build();
-
我配置的超时似乎没有效果。
为什么总是需要 20 秒才能响应。
请提出我遗漏或做错了什么。
【问题讨论】:
【参考方案1】:我配置的超时似乎没有效果。
您在这里设置了各种任意超时,所有这些都做不同的事情:
您的ReadTimeoutHandler
会在给定时间窗口内读取no 数据时触发。因此,如果 任何 数据在这 3 秒的窗口中仍然被读取,无论多么慢,它都不会触发。
WriteTimeoutHandler
为完成写入提供了一定的时间窗口 - 但除非您 发送 的基础请求(不等待响应)花费的时间超过该时间,否则这也不会出错.
CONNECT_TIMEOUT_MILLIS
是在发送任何数据之前实际建立 TCP 连接所需的时间。同样,除非花费超过 3 秒,否则它不会跳闸。
responseTimeout()
是在发送请求后读取完整响应所需的时间。请注意,这不包括发送请求之前可能需要的任何 DNS 解析、预热时间等。
我不知道你为什么要花 20 多秒的时间 - 这似乎太长了,整个请求在我的中等功率机器上执行,我的平均互联网连接最多几百毫秒。造成这种情况的原因可能是机器速度非常慢、互联网连接速度慢、DNS 服务器速度慢、网络速度慢、代理速度慢等等——但这不是你那里的代码的问题。
如果您希望 整个 链执行超时,包括它可能需要的任何后台请求、预热时间等 - 那么 AFAIK 实现这一点的唯一方法是单声道本身 -所以你的请求就变成了:
return webClient()
.get()
.uri("https://www.google.com")
.exchangeToMono(
response ->
System.out.println("Elapsed Time is: " + (System.currentTimeMillis() - startMillis));
if (response.statusCode().equals(HttpStatus.OK))
return Mono.just("OK");
return Mono.just("OK");
)
.timeout(Duration.ofMillis(500)); //Timeout specified here
【讨论】:
谢谢。当我在另一台机器上尝试时,它按预期工作。以上是关于为啥 WebFlux-WebClient 超时不起作用?的主要内容,如果未能解决你的问题,请参考以下文章