当前位置: 首页 > 知识库问答 >
问题:

当HttpStatus::Is4xClientError发生时,Webflux Webclient日志“未能发布消息”

沈思博
2023-03-14

我正在尝试使用Webflux WebClient从服务器下载zip文件。处理错误的正确方法是什么?

当服务器上存在文件时,一切正常。否则,我收到了Netty的警告,它无法发布消息。

return client.get()
      .uri(String.format("/cache/%s", filename))
      .accept(MediaType.APPLICATION_OCTET_STREAM)
      .retrieve()
      .onStatus(HttpStatus::is3xxRedirection, response -> Mono.error(new RuntimeException(response.statusCode().getReasonPhrase())))
      .onStatus(HttpStatus::is4xxClientError, response -> Mono.error(new RuntimeException(response.statusCode().getReasonPhrase())))
      .bodyToMono(ByteArrayResource.class)
      .subscribeOn(Schedulers.parallel())
      .map(res -> {
        try {
          InputStream is = res.getInputStream();
          File targetFile = Paths.get(cacheDir).resolve(filename).toAbsolutePath().toFile();
          FileUtils.copyInputStreamToFile(is, targetFile);
          LOG.info("File {} saved", targetFile.toPath());
        } catch (IOException e) {
          throw new RuntimeException("File download error from cache");
        }
        return true;
      });

我预计日志中不会有来自Netty的警告,但实际日志是:

WARN <reactor-http-epoll-4> Failed to release a message: DefaultLastHttpContent(data: PooledSlicedByteBuf(freed), decoderResult: success) (io.netty.util.ReferenceCountUtil:115)
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
    at io.netty.util.internal.ReferenceCountUpdater.toLiveRealRefCnt(ReferenceCountUpdater.java:74) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.internal.ReferenceCountUpdater.release(ReferenceCountUpdater.java:138) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.buffer.AbstractReferenceCountedByteBuf.release(AbstractReferenceCountedByteBuf.java:100) ~[netty-buffer-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.http.DefaultHttpContent.release(DefaultHttpContent.java:94) ~[netty-codec-http-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.ReferenceCountUtil.release(ReferenceCountUtil.java:88) ~[netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.ReferenceCountUtil.safeRelease(ReferenceCountUtil.java:113) [netty-common-4.1.36.Final.jar:4.1.36.Final]
    at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:120) [reactor-netty-0.8.9.RELEASE.jar:0.8.9.RELEASE]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) [netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [netty-codec-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1408) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) [netty-transport-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:796) [netty-transport-native-epoll-4.1.36.Final-linux-x86_64.jar:4.1.36.Final]
    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:432) [netty-transport-native-epoll-4.1.36.Final-linux-x86_64.jar:4.1.36.Final]
    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:333) [netty-transport-native-epoll-4.1.36.Final-linux-x86_64.jar:4.1.36.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:906) [netty-common-4.1.36.Final.jar:4.1.36.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) [netty-common-4.1.36.Final.jar:4.1.36.Final]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_202]

UPD。多亏了Thomas,当我像这样修改代码时,问题就解决了

.onStatus(HttpStatus::is3xxRedirection, exceptionFunction)
.onStatus(HttpStatus::is4xxClientError, exceptionFunction)
.....
.....
.....
private final Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction = response -> response.bodyToMono(String.class)
    .map(body -> new RuntimeException(String.format("%s, response body: %s", response.statusCode().toString(), body)));

共有1个答案

柴嘉禧
2023-03-14

留档声明如下:

当使用onStatus时,如果预期响应包含内容,那么onStatus回调应该使用它。否则,内容将自动排出,以确保释放资源。

关于检索()的正式文档最后一节。

这意味着如果发生错误时响应为空,那么框架将自动为您关闭连接。

另一方面,如果响应实际上有一些数据,则必须使用响应,以便关闭连接。

因此,您所做的是正确的,您可以记录响应,或在异常中发送响应。或者忽略它。但您需要像以前一样使用响应。

我也相信你可以回答。bodyToMono(Void.class)如果您只想处理它。

 类似资料:
  • zebra-client和zebra-cat-client的版本保持同步,不会单独发布版本。 zebra-dao版本单库维护。 推荐版本 zebra-client : 2.9.1 zebra-cat-client : 2.9.1 zebra-dao : 0.2.1 最新版本 zebra-client : 2.9.1 zebra-cat-client : 2.9.1 zebra-dao : 0.2.

  • 我已经在我的应用程序中正确配置了Crashlytics。我能看到坠机报告。 我试图添加一个自定义日志到崩溃报告,但我在报告中没有看到任何东西。我试图将日志移出UnaughtException处理程序,在这种情况下,我会看到日志。 myLog是一个非空的非空字符串(我检查了它)

  • 物联网有很多设备,通过这条指令可以向某个特定的物联网设备发送特定的消息内容。 请求方式: "|4|1|3|topic|message|" 参数: topic 设置订阅的topic,获取设备topic可参考教程 message 发布消息的内容 返回值: "|4|1|3|1|\r" 消息发送成功 "|4|1|3|2|\r" 消息发送失败 Arduino样例: softSerial.print("|4|

  • > 其中:构建文件'/home/jitpack/Build/Build.gradle'行:53 错误:评估根项目“构建”时出现问题。 找不到org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler类型对象上参数[目录“libs”]的方法实现()。 上面是我试图上传一个库到jitpack的日志(它没有任何应

  • 有关MysqlDump进程的问题。 在获取mysqldump时,是否发生了刷新日志?假设mysqldump运行单事务,那么会创建新的二进制日志文件吗?

  • 我正在使用Spring WebClient下载文件,如下所示: 文件下载得很好。我唯一挣扎的是,当响应为200时,我只想像这样记录一行: 我也试过了,但没有得到我想要的-如何记录Spring WebClient响应 简而言之,是否有某种方法可以在不编写单独的的情况下实现上述目标?在这里感到迷失和无知。这方面的任何指针都将受到高度赞赏。