java - Spring WebClient odd behaviour
问题描述
I am using the webClient
to execute an http request using the following code
@Bean
public CommandLineRunner commandLineRunner() {
return args -> Flux.just(1)
.flatMap(__ -> WebClient
.builder()
.build()
.post()
.uri("http://thisuridoesnotexist/")
.exchangeToMono(response -> Mono.just(1))
.doOnError(throwable -> System.out.println("1"))
.onErrorResume(
Exception.class,
throwable -> {
System.out.println("2");
return Mono.error(new RuntimeException("This vanishes"));
})
.onErrorContinue((throwable, o) -> {
System.out.println("8");
}))
.doOnError(__ -> System.out.println("9"))
.onErrorContinue((throwable, obj) -> System.out.println("10"))
.subscribe();
}
The issue actually occurs when the webClient
is trying to speak with a uri that is not answering and it throws a connection refused exception. As you can see in the code there are multiple Xerror
operators (which were placed just for the PoC of course ) But the only thing actually working here is the onErrorContinue
with the 8
. It is expected for the 9
and 10
not to work as the "error" is resolved on the 8
but! if I comment out the 8
then it skips 9
and goes directly to 10
. Lastly no matter the case it goes always skips the 1
and 2
operators.
Reading the documentation of reactor and the javadoc above doOnError
let say, it clearly states that for the Xerror
operators it cathces any exceptions which does not happen here.
Last but not least removing the onErrorContinue
the 1
, 2
and 9
work as expected. So if the onErrorContinue
is the issue that just consumes everything eagerly how can I use a "catchAll" failsafe incase an error is not "predicted" on specific cases or its just handled wrong?
just for the completion of the code the pom used in this demo-project is the following
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
解决方案
根据文档描述,这不是 Spring 的行为,而是onErrorContinue
:
通过从序列中删除犯罪元素并继续后续元素,让上游兼容的运算符从错误中恢复。通过提供的 BiConsumer 通知恢复的错误和相关值。或者,从该双消费者抛出的异常将向下游传播抛出的异常,以代替原始错误,该异常作为抑制异常添加到新错误中。
...
请注意,onErrorContinue() 是一个专业运算符,可以使您的反应链的行为不清楚。它在上游而不是下游运营商上运行,它需要特定的运营商支持才能工作,并且范围可以轻松地将上游传播到没有预料到的库代码中(导致意外行为。)
所以 doOnError 没有收到异常,因为上游已恢复。
为了理解它的真正含义以及如何处理它,我做了一些实验并发现,如果你把它throw new RuntimeException()
放在块8
中1
并被2
抓住。但不是9
, 因为相同的行为10
推荐阅读
- jenkins - 通过 Jenkins 错误执行 Katalon 套件
- python - 如何使用子进程将终端命令输出到 python gui 文本区域?
- python - PermissionError (WinError 31) 连接到系统的设备无法正常工作
- android - how to recognize Previous activity which is already finished
- objective-c - 默认应用已配置
- angular - 在 Angular2 中实现 ng2-toasty 时出错
- python-3.x - 无法在 anaconda 中安装软件包
- vb.net - how can I check if there is no winner in a tic tac toe game visual basic
- java - 为微调器项目赋予价值并在计算中使用它们
- python-3.x - pip install 给平台不支持错误