Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在WebClient中处理异常会引发io.netty.handler.TIMEOUTE.ReadTimeoutException_Java_Reactive Programming_Webclient_Spring Webflux_Project Reactor - Fatal编程技术网

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
类。始终处理您的异常