Spring Boot Webclient 抛出读取超时错误
Springboot Webclient throws readtimeout errors
Spring Web 客户端抛出大量读取超时(每秒加载 1000 个请求)。我正在使用 Spring引导版本 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);
}
}
如前所述on the Spring Framework issue you've opened(感谢!),这似乎不是 Framework 中的错误。
混淆来自这样一个事实,即当 运行 多个 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);
我没有收到任何读取超时。所以你的应用程序中的某些东西必须配置这样的超时。
Spring Web 客户端抛出大量读取超时(每秒加载 1000 个请求)。我正在使用 Spring引导版本 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);
}
}
如前所述on the Spring Framework issue you've opened(感谢!),这似乎不是 Framework 中的错误。
混淆来自这样一个事实,即当 运行 多个 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);
我没有收到任何读取超时。所以你的应用程序中的某些东西必须配置这样的超时。