首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >通过异常和传播错误对象中断反应管道

通过异常和传播错误对象中断反应管道
EN

Stack Overflow用户
提问于 2021-07-15 12:22:59
回答 1查看 176关注 0票数 0

当需要中断一个反应管道时,在反应编程方面,什么是最好的?

逻辑非常简单。

web服务、web应用程序将接受请求。

  • 第1步,从请求中,向第三方API发出第一个HTTP请求。在我们的示例中,第一个HTTP服务要么回答我们需要的字符串,要么回答我们不需要的字符串。
  • 步骤2,只有当步骤1以所需的内容进行响应时,才向第二个HTTP服务发出第二个HTTP请求,这也是无法控制的,以获得最终和最大的响应。

注意,这是顺序的,我们不能调用步骤2,除非我们从步骤1得到正确的值。

显然,此时对步骤2进行整个HTTP调用根本没有意义。

因此,我正考虑这样做:

代码语言:javascript
运行
复制
@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捕获它。

代码语言:javascript
运行
复制
@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 --在反应性的世界中都不是正确的方法。

我想请问,解决这个问题的正确方法是甚麽?

EN

Stack Overflow用户

回答已采纳

发布于 2021-07-15 15:08:42

您的虚拟Mono解决方案只起作用,因为链中没有任何东西需要进行任何额外的处理,如果在flatMap之后您需要对成功的值执行额外的flatMap怎么办?然后,当一个奇怪的假人Mono从链条上飞来时,你将陷入困境。

代码语言:javascript
运行
复制
.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

在反应堆中有很多处理错误的方法,我建议你把它们读一读,然后全部试一试。

4.6.2.处理运算符或函数中的异常

票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68393753

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档