WebClient 5.3+ 交换与 exchangeToMono。一起提取 cookie 和 body

WebClient 5.3+ exchange vs exchangeToMono. Extracting cookies and body together

我目前正在尝试处理通过 webClient 返回的整个请求。我需要能够阅读它附带的 bodycookies。但是,我目前在一次通话中同时执行这两项操作时遇到问题。下面我有两种方式来获取我想要的数据。我对使用 lambdas 和 webClient 还很陌生。我确实意识到 exchangeToMono() 是对 return Mono 或 Flux 的最新方法调用,因为在 exchange() 中发现了可能的内存泄漏。 我想说 subscribing() 到 return monoBody 可能对我有帮助,但到目前为止,我也没有运气以这种方式提取数据。谢谢大家的意见。

Mono<String> monoBody = webBuilder.build()
                .get()
                .uri(baseURI + "?Level=&pageSize=50&pageNo=&name=&id=&authToken=" + sessionToken)
                .accept(MediaType.ALL)
                .header("authToken", sessionToken)
                .header("x-Token", sessionToken)
                .header("X-token-X", sessionToken)
                .header("Ref", ref)
                .exchangeToMono(clientResponse -> clientResponse.bodyToMono(String.class));

 Mono<MultiValueMap<String,ResponseCookie>> monoMap = webBuilder.build()
                .get()
                .uri(baseURI + "?Level=&pageSize=50&pageNo=&unitName=&id=&authToken=" + sessionToken)
                .accept(MediaType.ALL)
                .header("authToken", sessionToken)
                .header("x-Token", sessionToken)
                .header("X-token-X", sessionToken)
                .header("Ref", ref)
                .exchangeToMono(clientResponse -> Mono.fromCallable(()-> clientResponse.cookies() ));
    

关于 Reactor API(由 WebClient 使用)要记住的关键是,您总是将操作组合成一个 'plan' 要做什么,然后在某个时候(订阅)您执行整个计划。

在您的情况下,您已经找到了两种获取所需信息的方法,但是对于 Reactive 流,您只能在流中的任何一点拥有一种类型,因此如果您需要两种类型的数据,您总是可以将它们组合成一个复合对象。

record DataWithCookies(MultiValueMap<String,ResponseCookie> cookies, String body){}

...
Mono<DataWithCookies> dataWithCookies =
      webBuilder.build()
                .get()
                .uri(baseURI + "?Level=&pageSize=50&pageNo=&unitName=&id=&authToken=" + sessionToken)
                .accept(MediaType.ALL)
                .header("authToken", sessionToken)
                .header("x-Token", sessionToken)
                .header("X-token-X", sessionToken)
                .header("Ref", ref)
                .exchangeToMono(response -> 
                    response.bodyToMono(String.class)
                            .map(stringBody -> new DataWithCookies(
                                                        stringBody, 
                                                        response.cookies())
                            )
                );

我使用了 previewed JDK 16 feature "Records" for brevity,但您可以使用简单的 class 作为 DataWithCookies

您现在有了一个 Mono,它将与 cookie 一起生成 body。为了便于阅读,您甚至可能想将该 lambda 提取到私有方法中。

                    ...
                    .exchangeToMono(this::extractBodyAndCookies);

...

private DataWithCookies extractBodyAndCookies(final ClientResponse response) {
    return response.bodyToMono(String.class)
                   .map(stringBody -> new DataWithCookies(stringBody, 
                                                          response.cookies())
                   );
}

另一种选择是使用 Tuples.of(stringBody, response.cookies()),这样可以避免在组合两个数据的同时创建另一种类型。