如何处理 Reactive Spring webflux 中的错误
How to handle errors in Reactive Spring webflux
因为有很多方法,例如 onErrorReturn、onErrorResume 等,所以在 Reactive Spring webflux for mono 和 flux 中,应该使用哪个方法来处理错误?
分享我的知识:
总共提供了六种方法来处理错误,下面讨论了五种方法:
onErrorReturn:return 整个流的回退值 (mono/flux)。例如。如果有 10 个元素的 flux,并且元素 3 发生错误,则 rest 4,5,6... 不会执行,而是考虑 fallback 值。
onErrorResume:return 整个流的 Mono/Flux 回退值 (mono/flux)。例如。如果有 10 个元素的 flux,并且元素 3 发生错误,则 rest 4,5,6... 不会执行,而是考虑 fallback 值。
onErrorContinue:消耗(错误,数据)并且不会将其拆分。它为错误元素考虑消费者,并为好的元素离开下游链。例如。如果有 10 个元素的通量,并且元素 3 发生错误,则除 3 之外的所有元素(1 到 10)将正常执行,但元素 3 将有不同的执行,如 onErrorContinue
的消费者中所述
doOnError:消耗错误并将其溢出。停止执行流中的其他元素。
onErrorMap:将一个错误转换为另一个错误。停止执行流中的其他元素。
所有这五种方法都有 3 种变体,
- 简单:直接考虑预期参数
- With Exception:考虑预期的参数,如果异常匹配class提供的异常
- With Predicate: 如果谓词为真,则考虑预期的参数
示例:
- onErrorReturn:return回退值
@Test
public void onErrorReturnDirectly_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(4)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorReturnIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(ArithmeticException.class, 4)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorReturnIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(error -> error instanceof ArithmeticException, 4)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorResume:return 回退值 Mono/Flux
@Test
public void onErrorResume_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(error -> Mono.just(4))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorResumeIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(
ArithmeticException.class,
error -> Mono.just(4)
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorResumeIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(
error -> error instanceof ArithmeticException,
error -> Mono.just(4)
)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorContinue:消耗(错误,数据)并且不会将其拆分。
@Test
public void onErrorContinue_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue((error, obj) -> log.info("error:[{}], obj:[{}]", error, obj ))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorContinueIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue(
ArithmeticException.class,
(error, obj) -> log.info("error:[{}], obj:[{}]", error, obj )
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorContinueIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue(
error -> error instanceof ArithmeticException,
(error, obj) -> log.info("error:[{}], obj:[{}]", error, obj )
)
.subscribe(num -> log.info("Number: {}", num ));
}
- doOnError:消耗错误并将其溢出
@Test
public void doOnError_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(error -> log.info("caught error"))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void doOnErrorIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(
ArithmeticException.class,
error -> log.info("caught error")
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void doOnErrorIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(
error -> error instanceof ArithmeticException,
error -> log.info("caught error")
)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorMap:将一个错误转化为另一个错误
@Test
public void OnErrorMap_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(error -> new RuntimeException("SomeMathException"))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void OnErrorMapIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(
ArithmeticException.class,
error -> new RuntimeException("SomeMathException")
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void OnErrorMapIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(
error -> error instanceof ArithmeticException,
error -> new RuntimeException("SomeMathException")
)
.subscribe(num -> log.info("Number: {}", num ));
}
因为有很多方法,例如 onErrorReturn、onErrorResume 等,所以在 Reactive Spring webflux for mono 和 flux 中,应该使用哪个方法来处理错误?
分享我的知识:
总共提供了六种方法来处理错误,下面讨论了五种方法:
onErrorReturn:return 整个流的回退值 (mono/flux)。例如。如果有 10 个元素的 flux,并且元素 3 发生错误,则 rest 4,5,6... 不会执行,而是考虑 fallback 值。
onErrorResume:return 整个流的 Mono/Flux 回退值 (mono/flux)。例如。如果有 10 个元素的 flux,并且元素 3 发生错误,则 rest 4,5,6... 不会执行,而是考虑 fallback 值。
onErrorContinue:消耗(错误,数据)并且不会将其拆分。它为错误元素考虑消费者,并为好的元素离开下游链。例如。如果有 10 个元素的通量,并且元素 3 发生错误,则除 3 之外的所有元素(1 到 10)将正常执行,但元素 3 将有不同的执行,如 onErrorContinue
的消费者中所述doOnError:消耗错误并将其溢出。停止执行流中的其他元素。
onErrorMap:将一个错误转换为另一个错误。停止执行流中的其他元素。
所有这五种方法都有 3 种变体,
- 简单:直接考虑预期参数
- With Exception:考虑预期的参数,如果异常匹配class提供的异常
- With Predicate: 如果谓词为真,则考虑预期的参数
示例:
- onErrorReturn:return回退值
@Test
public void onErrorReturnDirectly_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(4)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorReturnIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(ArithmeticException.class, 4)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorReturnIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorReturn(error -> error instanceof ArithmeticException, 4)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorResume:return 回退值 Mono/Flux
@Test
public void onErrorResume_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(error -> Mono.just(4))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorResumeIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(
ArithmeticException.class,
error -> Mono.just(4)
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorResumeIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorResume(
error -> error instanceof ArithmeticException,
error -> Mono.just(4)
)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorContinue:消耗(错误,数据)并且不会将其拆分。
@Test
public void onErrorContinue_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue((error, obj) -> log.info("error:[{}], obj:[{}]", error, obj ))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorContinueIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue(
ArithmeticException.class,
(error, obj) -> log.info("error:[{}], obj:[{}]", error, obj )
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void onErrorContinueIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorContinue(
error -> error instanceof ArithmeticException,
(error, obj) -> log.info("error:[{}], obj:[{}]", error, obj )
)
.subscribe(num -> log.info("Number: {}", num ));
}
- doOnError:消耗错误并将其溢出
@Test
public void doOnError_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(error -> log.info("caught error"))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void doOnErrorIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(
ArithmeticException.class,
error -> log.info("caught error")
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void doOnErrorIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.doOnError(
error -> error instanceof ArithmeticException,
error -> log.info("caught error")
)
.subscribe(num -> log.info("Number: {}", num ));
}
- onErrorMap:将一个错误转化为另一个错误
@Test
public void OnErrorMap_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(error -> new RuntimeException("SomeMathException"))
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void OnErrorMapIfArithmeticException_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(
ArithmeticException.class,
error -> new RuntimeException("SomeMathException")
)
.subscribe(num -> log.info("Number: {}", num ));
}
@Test
public void OnErrorMapIfPredicatePasses_Mono() {
Mono.just(2)
.map(i -> i/0) // will produce ArithmeticException
.onErrorMap(
error -> error instanceof ArithmeticException,
error -> new RuntimeException("SomeMathException")
)
.subscribe(num -> log.info("Number: {}", num ));
}