在另一种方法中处理来自 Spring WebClient 的错误

Rob*_*uch 6 spring spring-webclient

在 Spring Boot 应用程序中,我用来WebClient调用对远程应用程序的 POST 请求。该方法目前如下所示:

// Class A
public void sendNotification(String notification) {
    final WebClient webClient = WebClient.builder()
            .defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
            .build();
    webClient.post()
            .uri("http://localhost:9000/api")
            .body(BodyInserters.fromValue(notification))
            .retrieve()
            .onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
            .toBodilessEntity()
            .block();
    log.info("Notification delivered successfully");
}

// Class B
public void someOtherMethod() {
    sendNotification("test");
}
Run Code Online (Sandbox Code Playgroud)

用例是:另一个类中的方法调用sendNotification并且应该处理任何错误,即任何非 2xx 状态或者甚至无法发送请求。

但我正在努力处理WebClient. 据我了解,以下行将捕获除 2xx/3xx 之外的任何 HTTP 状态,然后返回Mono.error带有NotificationException(自定义异常扩展Exception)的 a。

onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))

但如何someOtherMethod()处理这种错误情况呢?它如何处理这个Mono.error?或者它实际上如何捕获NotificationExceptionifsendNotification甚至不将其放入签名中?

Auk*_*tis 11

嗯,处理错误的方法有很多,这实际上取决于发生错误时您想要做什么。

在您当前的设置中,解决方案很简单:首先,NotificationException应该扩展RuntimeException,因此,如果出现 HTTP 错误,.block()将抛出一个NotificationException. 最好将其添加到方法的签名中,并附上 Javadoc 条目。
在另一种方法中,您只需要捕获异常并对其执行您想要的操作。

/**
 * @param notification
 * @throws NotificationException in case of a HTTP error
 */
public void sendNotification(String notification) throws NotificationException {
    final WebClient webClient = WebClient.builder()
        .defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
        .build();
    webClient.post()
        .uri("http://localhost:9000/api")
        .body(BodyInserters.fromValue(notification))
        .retrieve()
        .onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
        .toBodilessEntity()
        .block();
    log.info("Notification delivered successfully");
}

public void someOtherMethod() {
    try {
        sendNotification("test");
    } catch (NotificationException e) {
        // Treat exception
    }
}
Run Code Online (Sandbox Code Playgroud)

在更具反应性的风格中,您可以返回 aMono并使用onErrorResume().

public Mono<Void> sendNotification(String notification) {
    final WebClient webClient = WebClient.builder()
        .defaultHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE)
        .build();
    return webClient.post()
        .uri("http://localhost:9000/api")
        .body(BodyInserters.fromValue(notification))
        .retrieve()
        .onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
        .bodyToMono(Void.class);
}

public void someOtherMethod() {
    sendNotification("test")
        .onErrorResume(NotificationException.class, ex -> {
            log.error(ex.getMessage());
            return Mono.empty();
        })
        .doOnSuccess(unused -> log.info("Notification delivered successfully"))
        .block();
}
Run Code Online (Sandbox Code Playgroud)

  • 这两种解决方案不是都是非反应性的吗?我们在两者中都使用了 block() 。 (2认同)