How to handle errors in Spring reactor Mono or Flux?
我在下面的代码中调整了Mono
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | try { return userRepository.findById(id) // step 1 .flatMap(user -> barRepository.findByUserId( user.getId()) // step 2 .map(bar-> Foo.builder().msg("Already exists").build()) // step 3 .switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build()) // step 4 .map(bar-> Foo.builder().msg("Created").build()) // step 5 )) .doOnError(throwable -> Mono.just(handleError(throwable))); } catch(Exception e) { log.error("from catch block"); return Mono.just(handleError(e)); } |
如果在第1步中发生错误(例如,指定的ID不存在用户),是否会被doOnError或try catch块捕获,或者这两个都不捕获?
同一问题,是否在步骤2,步骤3,步骤4中发生错误。
什么是正确的代码,以便始终由doOnError捕获错误并消除try catch?
我正在使用
handleError(throwable)仅执行log.error(e.getMessage()并重新调整Foo。
我认为第一个错误出现在标题中:"单声道或助焊剂"与错误处理无关。
- 单声道最多只能发射一项(流化一个元素)
- 助焊剂会散发出更复杂的东西(即清单)
要处理错误,您可以按照以下示例进行操作:
1 2 3 4 5 6 7 | return webClient.get() .uri(url) .retrieve() .bodyToMono(ModelYouAreRetrieving.class) .doOnError(throwable -> logger.error("Failed for some reason", throwable)) .onErrorReturn(new ModelYouAreRetrieving(...)) .block(); |
@Gianluca Pinto的最后一行代码也不正确。该代码不会被编译。 onErrorReturn不适合复杂的错误处理。您应该使用的是onErrorResume。
请参阅:https://grokonez.com/reactive-programming/reactor/reactor-handle-error#21_By_falling_back_to_another_Flux
onErrorResume将回退到另一个Flux,并让您捕获和管理先前Flux引发的异常。如果查看onErrorReturn的实现,您会发现onErrorReturn实际上是在使用onErrorResume。
所以这里的代码应该是:
1 | .onErrorResume(throwable -> Mono.just(handleError(throwable))); |
DoOnError仅会产生副作用,并且如果findById失败,则它会返回Mono.Error(),这应该是可行的。
1 2 3 4 5 6 7 8 9 | return userRepository.findById(id) .flatMap ( user -> barRepository.findByUserId(user.getId()) .map((user,bar)-> Foo.builder().msg("Already exists").build()) .switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build()) .map(bar-> Foo.builder().msg("Created").build()) )) .onErrorReturn(throwable -> Mono.just(handleError(throwable))); |
仅当您调用链的阻塞操作,或者在进入反应式链之前发生运行时错误时,try catch才起作用。
使用
处理
Below Code tries to covers User attributes in upper case. Now, when it encounters kyle the checked exception is throws and MIKE is returned from
onErrorReturn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @Test void Test19() { Flux.fromIterable(Arrays.asList(new User("jhon","10000"), new User("kyle","bot"))) .map(x -> { try { return toUpper(x); } catch (TestException e) { throw Exceptions.propagate(e); } }) .onErrorReturn(new User("MIKE","BOT")).subscribe(x -> System.out.println(x)); } protected final class TestException extends Exception { private static final long serialVersionUID = -831485594512095557L; } private User toUpper(User user) throws TestException{ if (user.getName().equals("kyle")) { throw new TestException(); } return new User(user.getName().toUpperCase(), user.getProfession().toUpperCase()); } |
输出
1 2 | User [name=JHON, profession=10000] User [name=MIKE, profession=BOT] |
@James Ralston的代码的最后一行是错误的。正确的代码应为:
1 2 3 4 5 6 7 8 9 | return userRepository.findById(id) .flatMap ( user -> barRepository.findByUserId(user.getId()) .map((user,bar)-> Foo.builder().msg("Already exists").build()) .switchIfEmpty(barRepository.save(Bar.builder().userId(user.getId()).build()) .map(bar-> Foo.builder().msg("Created").build()) )) .onErrorReturn(Mono.just(handleError(throwable))); |