将 Spring Webflux Mono 转换为 Either,最好不要阻塞?

Transforming a Spring Webflux Mono to an Either, preferably without blocking?

我正在使用 Kotlin 和 Arrow and the WebClient from spring-webflux. What I'd like to do is to transform a Mono instance to an Either

Either实例是在WebClient响应成功时调用Either.right(..)WebClientreturn响应时调用Either.left(..)创建的这是一个错误。

我正在寻找的是 Mono 中类似于 Either.fold(..) 的方法,我可以在其中映射成功和错误的结果,并且 return 与 Mono。像这样的东西(伪代码不起作用):

val either : Either<Throwable, ClientResponse> = 
                   webClient().post().exchange()
                                .fold({ throwable -> Either.left(throwable) },
                                      { response -> Either.right(response)})

怎么办?

我不太熟悉 Arrow 库,也不熟悉它的典型用例,所以我将使用 Java 片段来说明我的观点。

首先我想首先指出这种类型似乎是阻塞的而不是惰性的(不像 Mono)。将 Mono 转换为该类型意味着您将使您的代码阻塞并且您不应该这样做,例如,在 Controller 处理程序的中间,否则您将阻塞整个服务器。

这或多或少相当于:

Mono<ClientResponse> response = webClient.get().uri("/").exchange();
// blocking; return the response or throws an exception
ClientResponse blockingResponse = response.block();

话虽如此,我认为您应该能够将 Mono 转换为该类型,方法是在其上调用 block() 并在其周围调用 try/catch 方块,或者将其转动首先进入CompletableFuture,例如:

Mono<ClientResponse> response = webClient.get().uri("/").exchange();
Either<Throwable, ClientResponse> either = response
        .toFuture()
        .handle((resp, t) -> Either.fold(t, resp))
        .get();

可能有更好的方法来做到这一点(尤其是使用内联函数),但它们都应该首先涉及 Mono 上的阻塞。

Mono 上没有 fold 方法,但您可以使用以下两种方法实现相同的方法:maponErrorResume。它会是这样的:

val either : Either<Throwable, ClientResponse> = 
               webClient().post()
                          .exchange()
                          .map { Either.right(it) }
                          .onErrorResume { Either.left(it).toMono() }