在另一个方法中处理来自 Spring WebClient 的错误
Handling errors from Spring WebClient in another method
在 Spring 引导应用程序中,我使用 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");
}
用例是:另一个 class 中的方法调用 sendNotification
并且应该处理任何错误,即任何非 2xx 状态或请求甚至无法发送。
但我在 WebClient
中纠结于处理错误的概念。据我了解,以下行将捕获除 2xx/3xx 之外的任何 HTTP 状态,然后是 return 带有 NotificationException
的 Mono.error
(扩展 Exception
的自定义异常) .
onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
但是 someOtherMethod()
如何处理这种错误情况?它如何处理这个 Mono.error
?或者如果 sendNotification
甚至没有将它扔到签名中,它如何实际捕获 NotificationException
?
使用 imperative/blocking 样式,您可以用 try-catch 包围它:
try {
webClient.post()
.uri("http://localhost:9000/api")
.body(BodyInserters.fromValue(notification))
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
.toBodilessEntity()
.block();
} catch(NotificationException e) {...}
反应性解决方案是像这样使用 onErrorResume
运算符:
webClient.post()
.uri("http://localhost:9000/api")
.body(BodyInserters.fromValue(notification))
.retrieve()
.onErrorResume(e -> someOtherMethod())
.toBodilessEntity()
.block();
此处,反应式方法someOtherMethod()
将在任何错误的情况下执行。
嗯,有很多方法可以处理错误,这实际上取决于您在出现错误时想做什么。
在您当前的设置中,解决方案很简单:首先,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
}
}
在更被动的风格中,您可以 return a Mono
并使用 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();
}
在 Spring 引导应用程序中,我使用 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");
}
用例是:另一个 class 中的方法调用 sendNotification
并且应该处理任何错误,即任何非 2xx 状态或请求甚至无法发送。
但我在 WebClient
中纠结于处理错误的概念。据我了解,以下行将捕获除 2xx/3xx 之外的任何 HTTP 状态,然后是 return 带有 NotificationException
的 Mono.error
(扩展 Exception
的自定义异常) .
onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
但是 someOtherMethod()
如何处理这种错误情况?它如何处理这个 Mono.error
?或者如果 sendNotification
甚至没有将它扔到签名中,它如何实际捕获 NotificationException
?
使用 imperative/blocking 样式,您可以用 try-catch 包围它:
try {
webClient.post()
.uri("http://localhost:9000/api")
.body(BodyInserters.fromValue(notification))
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> Mono.error(NotificationException::new))
.toBodilessEntity()
.block();
} catch(NotificationException e) {...}
反应性解决方案是像这样使用 onErrorResume
运算符:
webClient.post()
.uri("http://localhost:9000/api")
.body(BodyInserters.fromValue(notification))
.retrieve()
.onErrorResume(e -> someOtherMethod())
.toBodilessEntity()
.block();
此处,反应式方法someOtherMethod()
将在任何错误的情况下执行。
嗯,有很多方法可以处理错误,这实际上取决于您在出现错误时想做什么。
在您当前的设置中,解决方案很简单:首先,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
}
}
在更被动的风格中,您可以 return a Mono
并使用 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();
}