【问题标题】:Springboot Webclient throws readtimeout errorsSpring Boot Webclient 抛出 readtimeout 错误
【发布时间】:2019-05-16 02:52:50
【问题描述】:

Spring Webclient 会引发大量读取超时(每秒加载 1000 个请求时)。我正在使用 Springboot 版本 2.1.1.RELEASE。请在下面找到代码,如果我缺少任何配置,请告诉我:

@Bean
public WebClient webClient() {
    return WebClient.builder().build();
}

public Mono<String> post(String url, JSONObject body) {

    Mono<String> result = webClient.post().uri(url)
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON_UTF8)
            .body(BodyInserters.fromObject(body))
            .exchange()
            .flatMap { clientResponse ->
        return handleResponse(clientResponse)
    }
    return result;
}

private Mono<String> handleResponse(ClientResponse clientResponse) {
         if (clientResponse.statusCode().is4xxClientError() || clientResponse.statusCode().is5xxServerError()) {
            return clientResponse.bodyToMono(String.class)
                    .flatMap { errorBody ->
                return Mono.error(new CustomException(errorBody, clientResponse.statusCode().value()))
            }
        } else {
            return clientResponse.bodyToMono(String.class);
        }
    }

【问题讨论】:

  • 您能提供更多信息吗?您是否为客户端配置了超时?你能分享错误的堆栈跟踪吗?使用 JMeter 请求远程服务时,您得到的最大延迟是多少?
  • @BrianClozel @Bean public WebClient webClient() { TcpClient tcpClient = TcpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000) .doOnConnected { connection -&gt; connection.addHandlerLast(new ReadTimeoutHandler(5)) .addHandlerLast(new WriteTimeoutHandler(30)) } ReactorClientHttpConnector httpConnector = new ReactorClientHttpConnector(HttpClient.from(tcpClient)); return WebClient.builder() .clientConnector(httpConnector) .build(); }
  • @BrianClozel 我尝试了上面的超时配置以及默认的WebClient.builder().build();。在这两种情况下,我都会收到 readtimeout 异常
  • 您能否在交换后添加一个 « log() » 运算符并在此处与日志一起报告?
  • @BrianClozel Pooled connection observed an error 2018-12-17T18:13:36.903185649Z io.netty.handler.timeout.ReadTimeoutException: null 这是我得到的错误日志。

标签: spring-boot spring-webflux


【解决方案1】:

正如on the Spring Framework issue you've opened 所说(谢谢!),这似乎不是框架中的错误。

混淆来自这样一个事实:当同时运行多个 Web 客户端请求并在响应式管道上添加 log 运算符以获取更多信息时,日志让您认为即使请求只是触发了读取超时制作。

如果我没记错的话,您在日志中看到的后缀编号(例如 reactor.Mono.SwitchIfEmpty.48759)与订阅者相关联。

就您而言,这意味着

13:55:50.287 [reactor-http-nio-6] INFO reactor.Mono.MapFuseable.49127 - | request(unbounded) 

13:55:50.312 [reactor-http-nio-6] ERROR reactor.Mono.SwitchIfEmpty.48759 - onError(

不是关于相同的 HTTP 请求。 Reactor 在工作线程上调度任务,因此当您看到事情在同一个线程上按顺序发生时,这并不意味着这些工作单元正在为同一个订阅者完成。

如果您在日志中跟踪订阅者 ID,您应该会看到请求数据和未获取数据之间的时间量约为 5 秒。

最后一点,我创建了一个 Reactor HTTP 服务器,它在 10 秒后发送响应正文:

HttpServer.create().host("localhost").port(8080).handle((req, res) -> {
    return res.sendString(Flux.just("Hello")
        .delayElements(Duration.ofSeconds(10)), StandardCharsets.UTF_8);
}).bindNow().onDispose().block();

还有一个获取此数据的 WebClient:

String response = WebClient.create().get().uri("http://localhost:8080/")
    .retrieve().bodyToMono(String.class).log().block();
System.out.println(response);

我没有收到任何读取超时。所以你的应用程序中的某些东西必须配置这样的超时。

【讨论】:

    猜你喜欢
    • 2021-06-02
    • 2017-06-09
    • 2021-10-13
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    • 2021-07-21
    • 2018-12-01
    相关资源
    最近更新 更多