当需要中断一个反应管道时,在反应编程方面,什么是最好的?
逻辑非常简单。
web服务、web应用程序将接受请求。
注意,这是顺序的,我们不能调用步骤2,除非我们从步骤1得到正确的值。
显然,此时对步骤2进行整个HTTP调用根本没有意义。
因此,我正考虑这样做:
@PostMapping(path = "/question")
public Mono<ResponseEntity<String>> createDummyMono(String theImportantKey) {
    return WebClient.create("http://first-service.com/get" + theImportantKey).get().exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class))
            .flatMap(extractGoodValueFromStepOne -> {
                if (extractGoodValueFromStepOne.startsWith("good")) {
                    System.out.println("Great! Step1 responded with something starting with good! Only with this we should invoke the second API");
                    return WebClient.create("http://second-service.com/get" + extractGoodValueFromStepOne.substring(4)).get().exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class));
                } else {
                    System.out.println("This is bad, Step 1 did not return something starting with good, no need to make the second API call then. Let's just propagate an error message all the way to response with a dummy Mono");
                    return Mono.just("Step 1 did not answer with something good, the ultimate answer is an error");
                }
            })
            .map(ResponseEntity::ok);
}在这个逻辑中,由flatMap代表的第二步将查看步骤1是否响应了我们需要的东西。只有在这种情况下,才会向步骤2发出第二个HTTP请求。但是,如果不是,我将构建一个虚拟Mono来传播和执行响应管道。
第二个解决方案是抛出一个异常,例如用@ExceptionHandler捕获它。
@PostMapping(path = "/question")
public Mono<ResponseEntity<String>> throwRuntimeException(String theImportantKey) {
    return WebClient.create("http://first-service.com/get" + theImportantKey).get().exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class))
    .flatMap(extractGoodValueFromStepOne -> {
        if (extractGoodValueFromStepOne.startsWith("good")) {
            System.out.println("Great! Step1 responded with something starting with good! Only with this we should invoke the second API");
            return WebClient.create("http://second-service.com/get" + extractGoodValueFromStepOne.substring(4)).get().exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class));
        } else {
            System.out.println("This is bad, Step 1 did not return something starting with good, no need to make the second API call then. Let's just propagate an error message all the way to response with a dummy Mono");
            throw new RuntimeException("Step 1 did not answer with something good, the ultimate answer is an error");
        }
    })
    .map(ResponseEntity::ok);
}
@ExceptionHandler
public Mono<ResponseEntity<String>> exception(final RuntimeException runtimeException) {
    return Mono.just(ResponseEntity.ok("Step 1 did not answer with something good, the ultimate answer is an error"));
}在这里,逻辑是一样的。如果步骤1没有回答我们需要的内容,我就会抛出一个RuntimeException来中断管道。
我有点认为,第一个解决方案--传递一些虚拟的Mono或者抛出一个未经检查的RuntimeException --在反应性的世界中都不是正确的方法。
我想请问,解决这个问题的正确方法是甚麽?
发布于 2021-07-15 15:08:42
您的虚拟Mono解决方案只起作用,因为链中没有任何东西需要进行任何额外的处理,如果在flatMap之后您需要对成功的值执行额外的flatMap怎么办?然后,当一个奇怪的假人Mono从链条上飞来时,你将陷入困境。
.flatMap(value -> {
    if (value.startsWith("good")) {
        System.out.println("good");
        return WebClient.create("http://second-service.com/get" + value.substring(4))
                        .get()
                        .exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class));
     } else {
         System.out.println("Boo");
         return Mono.just("some value");
     }
}).flatMap(value2 -> {
    // what now?
})当在操作符中抛出异常时,异常将作为onError事件在流中传播。例如,当我们返回一个Mono#error时。
例如,某些异常(例如OutOfMemoryException)将不被视为异常,而是fatal事件,并将立即终止流。
但是,通常情况下,异常将通过链传输,而“常规”运算符会认为这是一个错误事件,因此他们将跳过该事件并将其传递到调用客户端,或者直到任何专门的错误事件处理程序看到它,或者像在您的情况下被您定义的异常处理程序所抢夺。
在您的情况下,正确的方法是返回一个Mono#error (因此您的返回是显式的),如果发生这种情况,我们将返回一个错误,然后您可以恢复、删除值或做任何您想做的事情,或者像您所做的那样使用一个异常处理程序来处理异常。
第一个解决方案的行为更像是返回空,然后有switchIfEmpty操作符,因此如果最后一个操作符返回为空,则改为另一个publisher (Mono)。或者您可以使用onErrorResume,如果出现特定错误,则返回回退Publisher。
在反应堆中有很多处理错误的方法,我建议你把它们读一读,然后全部试一试。
https://stackoverflow.com/questions/68393753
复制相似问题