使用 Spring 的 WebClient 和 blocking/syncronous 请求捕获 try/catch 的异常
Catch exceptions with try/catch using Spring's WebClient with blocking/syncronous request
我需要发出一个同步的、阻塞的请求,我正在使用Spring的WebClient
而不是Spring' s RestTemplate
因为后者被弃用了。在这种情况下,我不需要响应式功能,我只想以一种直接的方式使用 REST API,而不包括额外的依赖项。
我有以下代码,可以正常工作:
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.bodyToMono( MyObject.class )
.block()
但是,我需要处理无法连接到 API 或连接但收到 4xx/5xx 代码的情况。
所以,直接的方法是将调用放在 try/catch 中,然后捕获 Spring 的 WebClientResponseException
,它由 .bodyToMono
抛出,如果它得到一个 4xx/5xx 代码:
import org.springframework.web.reactive.function.client.WebClientResponseException;
try {
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.bodyToMono( MyObject.class )
.block()
}
catch ( WebClientResponseException e ) {
// Logic to handle the exception.
}
这工作正常,但如果连接被拒绝(例如,如果 URL 错误或服务已关闭)则不起作用。在这种情况下,我在控制台中得到以下信息:
reactor.core.Exceptions$ErrorCallbackNotImplemented:
io.netty.channel.AbstractChannel$AnnotatedConnectException:
finishConnect(..) failed: Connection refused: /127.0.0.1:8090 Caused
by: io.netty.channel.AbstractChannel$AnnotatedConnectException:
finishConnect(..) failed: Connection refused: /127.0.0.1:8090
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has
been observed at the following site(s):
|_ checkpoint ⇢ Request to GET http://127.0.0.1:8090/test [DefaultWebClient] Stack trace: Caused by: java.net.ConnectException:
finishConnect(..) failed: Connection refused
at io.netty.channel.unix.Errors.throwConnectException(Errors.java:124)
~[netty-transport-native-unix-common-4.1.48.Final.jar:4.1.48.Final]
(...)
我不确定我需要捕获哪个异常来处理这种情况。
除此之外,我还想在连接被拒绝时抛出一个自定义异常,在收到错误代码时抛出一个不同的自定义异常。在第二种情况下,我尝试使用 .onStatus
方法:
try {
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.onStatus( HttpStatus::is4xxClientError, response -> {
return Mono.error( new CustomClientException( "A client error ocurred" ) );
})
.bodyToMono( MyObject.class )
.block()
}
catch ( CustomClientException e ) {
// Logic to handle the exception.
}
但是在 catch 块中没有捕获异常,尽管堆栈跟踪确实出现在控制台上。
有没有办法使用 try/catch 块来处理 4xx/5xx 代码和连接错误,希望有自定义例外?或者我应该使用不同的网络客户端 and/or 改变我的方法吗?我对反应式编程不熟悉。
提前致谢。
使用 retrieve()
,底层 HTTP 客户端上发生的所有异常都包装在名为 ReactiveException
的 RuntimeException
中。这样做是为了通过反应接口冒泡已检查的异常。
在Exceptions.unwrap()
中提供了一种获取实际包装异常的方法。然后您可以抛出未包装的异常,稍后可以在适当的时候捕获它。执行此操作的一种方法如下:
void makeHttpCall(..) throws Exception {
try {
// ..
// webclient request code
// ..
} catch(Exception e) {
throw Exceptions.unwrap(e);
}
}
// somewhere else:
try {
makeHttpCall(..);
} catch (ConnectException e) {
// Do your specific error handling
}
我不太喜欢用 throws Exception
声明一个方法,但在这一点上它根本不知道它可能是什么。
我需要发出一个同步的、阻塞的请求,我正在使用Spring的WebClient
而不是Spring' s RestTemplate
因为后者被弃用了。在这种情况下,我不需要响应式功能,我只想以一种直接的方式使用 REST API,而不包括额外的依赖项。
我有以下代码,可以正常工作:
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.bodyToMono( MyObject.class )
.block()
但是,我需要处理无法连接到 API 或连接但收到 4xx/5xx 代码的情况。
所以,直接的方法是将调用放在 try/catch 中,然后捕获 Spring 的 WebClientResponseException
,它由 .bodyToMono
抛出,如果它得到一个 4xx/5xx 代码:
import org.springframework.web.reactive.function.client.WebClientResponseException;
try {
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.bodyToMono( MyObject.class )
.block()
}
catch ( WebClientResponseException e ) {
// Logic to handle the exception.
}
这工作正常,但如果连接被拒绝(例如,如果 URL 错误或服务已关闭)则不起作用。在这种情况下,我在控制台中得到以下信息:
reactor.core.Exceptions$ErrorCallbackNotImplemented: io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:8090 Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: Connection refused: /127.0.0.1:8090 Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): |_ checkpoint ⇢ Request to GET http://127.0.0.1:8090/test [DefaultWebClient] Stack trace: Caused by: java.net.ConnectException: finishConnect(..) failed: Connection refused at io.netty.channel.unix.Errors.throwConnectException(Errors.java:124) ~[netty-transport-native-unix-common-4.1.48.Final.jar:4.1.48.Final] (...)
我不确定我需要捕获哪个异常来处理这种情况。
除此之外,我还想在连接被拒绝时抛出一个自定义异常,在收到错误代码时抛出一个不同的自定义异常。在第二种情况下,我尝试使用 .onStatus
方法:
try {
MyObject object = webClient.get()
.uri( myUri )
.retrieve()
.onStatus( HttpStatus::is4xxClientError, response -> {
return Mono.error( new CustomClientException( "A client error ocurred" ) );
})
.bodyToMono( MyObject.class )
.block()
}
catch ( CustomClientException e ) {
// Logic to handle the exception.
}
但是在 catch 块中没有捕获异常,尽管堆栈跟踪确实出现在控制台上。
有没有办法使用 try/catch 块来处理 4xx/5xx 代码和连接错误,希望有自定义例外?或者我应该使用不同的网络客户端 and/or 改变我的方法吗?我对反应式编程不熟悉。
提前致谢。
使用 retrieve()
,底层 HTTP 客户端上发生的所有异常都包装在名为 ReactiveException
的 RuntimeException
中。这样做是为了通过反应接口冒泡已检查的异常。
在Exceptions.unwrap()
中提供了一种获取实际包装异常的方法。然后您可以抛出未包装的异常,稍后可以在适当的时候捕获它。执行此操作的一种方法如下:
void makeHttpCall(..) throws Exception {
try {
// ..
// webclient request code
// ..
} catch(Exception e) {
throw Exceptions.unwrap(e);
}
}
// somewhere else:
try {
makeHttpCall(..);
} catch (ConnectException e) {
// Do your specific error handling
}
我不太喜欢用 throws Exception
声明一个方法,但在这一点上它根本不知道它可能是什么。