首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WebClient.exchangeToMono WebFlux 5.3.0 - Spring ()

WebClient.exchangeToMono WebFlux 5.3.0 - Spring ()
EN

Stack Overflow用户
提问于 2020-11-03 01:59:43
回答 2查看 13.2K关注 0票数 9

我刚刚升级到Webflux 5.3.0,注意到WebClient.exchange()方法现在已弃用(link)支持新方法.exchangeToMono()和.exchangeToFlux()

我有这样的代码:

代码语言:javascript
运行
复制
webClient
   .method(request.method)
   .uri(request.path)
   .body(request.bodyToMono())
   .exchange()
   .flatMap { response ->
      ServerResponse.
         .status(response.statusCode())
         .headers { it.addAll(response.headers().asHttpHeaders()) }
         .body(response.bodyToMono())
   }

我不得不把它重构成这样:

代码语言:javascript
运行
复制
.exchangeToMono { response ->
      ServerResponse.
         .status(response.statusCode())
         .headers { it.addAll(response.headers().asHttpHeaders()) }
         .body(response.bodyToMono())
   }

但是,显然,.exchangeToMono()调用.releaseIfNotConsumed(),这将释放未处理的响应主体,并基本上使服务器返回一个空主体

所以我不得不进一步重构我的代码:

代码语言:javascript
运行
复制
.exchangeToMono { response ->
      response.bodyToMono()
         .defaultIfEmpty(ByteArray(0))
         .flatMap { body ->
            ServerResponse.
               .status(response.statusCode())
               .headers { it.addAll(response.headers().asHttpHeaders()) }
               .bodyValue(body)
         }
   }

据我所知,.exchange()允许我的代理服务器在没有实际处理的情况下传输响应正文,而.exchangeToMono()强制我处理(buffer?)它。这是正确的吗?

如果是这样,其影响是什么?我应该接受更改,还是应该以某种方式调整代码,使其在不处理响应正文的情况下传输响应正文?我该怎么做呢?

=

tl;dr通过的实际区别是什么?.body(response.bodyToMono()).bodyValue(body)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-11-03 20:39:00

在通读了更改并试图理解您的问题后,我将尝试回答这个问题。我不确定这是不是正确的答案,我将根据我对reactor、webflux和webclient的了解做出一些逻辑假设。

自从WebClient发布以来,主要的主力应该是retrieve()能够针对完全异步的but客户端提供简单但稳定的API。

问题是大多数人习惯于使用ResponseEntities由旧的已弃用的RestTemplate所以ppl转而使用exchange()函数。

但问题就在这里。当您获得对Response你也有一个与之相关的责任。您有义务使用response

以便服务器可以关闭TCP连接。这通常意味着您需要读取头部和正文,然后我们才能关闭连接。

如果您不使用响应,您将拥有一个打开的连接,这会导致内存泄漏。

Spring通过提供如下函数解决了这个问题response#bodyToMonoresponse#bodyToFlux它使用正文,然后关闭响应(这又关闭连接,从而使用响应)。

但事实证明,对于人们来说,编写不使用响应的代码非常容易(因为开发人员都是诡计多端的混蛋),因此会产生悬而未决的TCP连接。

代码语言:javascript
运行
复制
webclient.url( ... )
    .exchange(response -> {

        // This is just an example but, but here i just re-return the response
        // which means that the server will keep the connection open, until i 
        // actually consume the body. I could send this all over my application
        // but never consume it and the server will keep the connection open as
        // long as i do, could be a potential memory leak.

        return Mono.just(response)
    }

新的exchangeToMono实现基本上会强制您使用正文,以避免内存泄漏。如果您想要处理原始响应,您将被迫使用正文。

下面我们来谈谈你的例子和你的需求。

您只需要将请求从一台服务器代理到另一台服务器即可。你确实消耗了身体,但不是在flatMap离WebClient很近。

代码语言:javascript
运行
复制
.exchange()
   .flatMap { response ->
      ServerResponse.
         .status(response.statusCode())
         .headers { it.addAll(response.headers().asHttpHeaders()) }
         .body(response.bodyToMono()) 
         // Here you are declaring you want to consume but it isn't consumed right here, its not consumed until much later.
   }

在您的代码中,您将返回一个ServerResponse但你必须时刻想着。

订阅之前什么都不会发生..。您基本上是在传递一个很长的ServerResponse但你还没有吃掉尸体。您只声明了当服务器需要正文时,它将不得不使用获取新正文的最后一个响应的正文。

这样想,您将返回一个ServerResponse它只包含我们想要的东西的声明,而不是实际的东西。

方法返回此参数时,flatMap它将一直传输到应用程序之外,直到我们将其编写为对客户端打开的TCP连接的响应。

只有在那时才会构建响应,也就是使用和关闭来自WebClient的第一个响应的时候。

因此,您的原始代码是有效的,因为您确实使用了WebClient响应,只是在向调用客户端编写响应之前并没有这样做。

你所做的并不是天生的错误,只是以这种方式使用WebClient API会增加人们错误使用它的风险,并且可能会发生内存泄漏。

我希望这至少回答了你的一些问题,我主要是写下我对这个变化的解释。

票数 15
EN

Stack Overflow用户

发布于 2021-02-27 00:25:50

作为向后兼容性的安全解决方法:

代码语言:js
复制
exchangeToMono(rs -> Mono.just(rs.mutate().build)))

你仍然会收到ClientResponse使用原始数据消耗/释放所有数据的下游类型ClientResponse期间mutate()..。别忘了释放变异的一个。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64650820

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档