Java 在WebClient中处理异常会引发io.netty.handler.TIMEOUTE.ReadTimeoutException
所以我对反应式编程是新手,我写了一些代码,我想测试一下。这些是更多的集成测试,因为我正在实时复制文件,稍后检查它们是否相同。我有一个Java 在WebClient中处理异常会引发io.netty.handler.TIMEOUTE.ReadTimeoutException,java,reactive-programming,webclient,spring-webflux,project-reactor,Java,Reactive Programming,Webclient,Spring Webflux,Project Reactor,所以我对反应式编程是新手,我写了一些代码,我想测试一下。这些是更多的集成测试,因为我正在实时复制文件,稍后检查它们是否相同。我有一个MockWebServer将我的响应模拟为4xx,这在代码中处理得很好。不幸的是,我也得到了io.netty.handler.timeout.ReadTimeoutException,这掩盖了我的自定义WebClient响应异常,因此在测试中我得到了错误的异常。基本上我有两个问题,为什么我会得到这个io.netty.handler.timeout.ReadTimeo
MockWebServer
将我的响应模拟为4xx
,这在代码中处理得很好。不幸的是,我也得到了io.netty.handler.timeout.ReadTimeoutException
,这掩盖了我的自定义WebClient响应异常
,因此在测试中我得到了错误的异常。基本上我有两个问题,为什么我会得到这个io.netty.handler.timeout.ReadTimeoutException
异常?由于某种原因,它只出现在doError()
方法之后,我甚至不知道为什么会发生这种情况
现在代码是同步的,我很清楚这一点
第二个问题是,在给定的重试次数后,如何处理测试中的自定义异常?现在是3,只有到那时我才希望抛出我的另一个异常
代码如下:
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(targetPath, StandardOpenOption.WRITE);
Flux<DataBuffer> fileDataStream = Mono.just(filePath)
.map(file -> targetPath.toFile().exists() ? targetPath.toFile().length() : 0)
.map(bytes -> webClient
.get()
.uri(uri)
.accept(MediaType.APPLICATION_OCTET_STREAM)
.header("Range", String.format("bytes=%d-", bytes))
.retrieve()
.onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new CustomException("4xx error")))
.onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new CustomException("5xx error")))
.bodyToFlux(DataBuffer.class)
.doOnError(throwable -> log.info("fileDataStream onError", throwable))
)
.flatMapMany(Function.identity());
return DataBufferUtils
.write(fileDataStream, fileChannel)
.map(DataBufferUtils::release)
.doOnError(throwable -> {
try {
fileChannel.force(true);
} catch (IOException e) {
throw new WritingException("failed force update to file channel", e);
}
})
.retry(3)
.doOnComplete(() -> {
try {
fileChannel.force(true);
} catch (IOException e) {
log.warn("failed force update to file channel", e);
throw new WritingException("failed force update to file channel", e);
}
})
.doOnError(throwable -> targetPath.toFile().delete())
.then(Mono.just(target));
AsynchronousFileChannel fileChannel=AsynchronousFileChannel.open(targetPath,StandardOpenOption.WRITE);
Flux fileDataStream=Mono.just(文件路径)
.map(文件->targetPath.toFile().exists()?targetPath.toFile().length():0)
.map(字节->网络客户端)
.get()
.uri(uri)
.accept(MediaType.APPLICATION\u八位字节\u流)
.header(“范围”,字符串.format(“字节=%d-”,字节))
.retrieve()
.onStatus(HttpStatus::is4xclientorror,clientResponse->Mono.error(新自定义异常(“4xx错误”))
.onStatus(HttpStatus::is5xxServerError,clientResponse->Mono.error(新的CustomException(“5xx错误”))
.bodyToFlux(数据缓冲级)
.doon错误(可丢弃->log.info(“fileDataStream onError”,可丢弃))
)
.flatMapMany(Function.identity());
返回数据缓冲区
.write(文件数据流、文件通道)
.map(数据缓冲区::发布)
.doon错误(可丢弃->{
试一试{
fileChannel.force(true);
}捕获(IOE异常){
抛出新的写入异常(“强制更新文件通道失败”,e);
}
})
.重试(3)
.doOnComplete(()->{
试一试{
fileChannel.force(true);
}捕获(IOE异常){
log.warn(“强制更新文件通道失败”,e);
抛出新的写入异常(“强制更新文件通道失败”,e);
}
})
.doError(可丢弃->目标路径.toFile().delete())
.然后(单声道刚刚(目标));
响应是Mono
,因为我只对新创建和复制的文件的路径感兴趣
欢迎对代码提出任何意见
复制机制是基于这个线程制作的,所以问题基本上在测试中。我有一个MockResponse
只排队到MockWebServer
一次,所以在WebClient中重试时,mocked服务器没有任何响应集(基本上它的行为就像根本不可用一样,因为没有模拟响应)
为了能够在服务器完全停机的情况下处理异常,我认为值得在您的流量链中添加这样的行:
.doOnError(ChannelException.class, e -> {
throw new YourCustomExceptionForHandlingServerIsDownSituation("Server is unreachable", e);
})
这将帮助您从Netty处理ReadTimeoutException
(如果无法访问服务器),因为它扩展了ChannelException
类。始终处理您的异常