Spring5之WebClient简单使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring5之WebClient简单使用相关的知识,希望对你有一定的参考价值。
参考技术A Spring3.0引入了RestTemplate,但是在后来的官方源码中介绍,RestTemplate有可能在未来的版本中被弃用,所谓替代RestTemplate,在Spring5中引入了WebClient作为非阻塞式Reactive Http客户端。采用阻塞IO模式获取输入数据。每个连接都需要独立的线程,完成数据输入、业务处理、返回。传统阻塞IO模型的问题是,当并发数很大时,就要创建大量线程,占用很大的系统资源。连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源浪费。
SpringMVC或Struct等框架都是基于Servlet的,其底层IO模型是阻塞IO模型。Spring社区为了解决SpringMVC的阻塞模型在高并发场景下的性能瓶颈,推出了Spring WebFlux,WebFlux底层实现是久经考验的Netty非阻塞IO通信框架。其实WebClient处理单个HTTP请求的响应时长并不比RestTemplate更快,但是它处理并发的能力更强。 所以响应式非阻塞IO模型的核心意义在于,提高了单位时间内有限资源下的服务请求的并发处理能力,而不是缩短了单个服务请求的响应时长。
uriBuilderFactory:自定义UriBuilderFactory灵活配置使用Url
defaultHeader:为HTTP请求设置Headers请求头
defaultCookie:为HTTP请求设置Cookies
defaultRequest:自定义HttpRequest
filter:为HTTP请求增加客户端过滤器
exchangeStrategies:HTTP读写信息自定义
clientConnector:HTTP客户端连接器设置
使用Mono和Flux接收返回结果,一个Mono对象包含0个或1个元素,而一个Flux对象包含1个或多个元素。
如何从 Spring WebClient 获取响应 json
【中文标题】如何从 Spring WebClient 获取响应 json【英文标题】:How to get response json from Spring WebClient 【发布时间】:2020-10-30 12:39:45 【问题描述】:我一直在尝试遵循最简单的教程来了解如何使用 WebClient
,据我了解,与 RestTemplate
相比,它是下一个最棒的东西。
例如,https://www.baeldung.com/spring-5-webclient#4-getting-a-response
所以当我尝试对应该返回一些 json 的 https://petstore.swagger.io/v2/pet/findByStatus?status=available 做同样的事情时,
WebClient webClient = WebClient.create();
webClient.get().uri("https://petstore.swagger.io/v2/pet/findByStatus?status=available").exchange().block();
我完全不知道如何从生成的DefaultClientResponse
对象着手。到达物理反应体不应该这么复杂,但我跑题了。
如何使用我提供的代码获取响应正文?
【问题讨论】:
“当我尝试同样的事情时”,你不是在做同样的事情吗?您没有对客户响应做任何事情,例如映射它,或者调用bodyToMono
将主体映射到一个类型...
哇....我想通了
【参考方案1】:
以您目前拥有的形式,并解释行为..
WebClient webClient = WebClient.create();
webClient.get()
.uri("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.exchange()
.block();
block()
通过内部同步订阅Mono
来启动请求,并返回结果ClientResponse
。您也可以通过在exchange()
方法返回的Mono
上调用subscribe()
来异步处理此问题,而不是block()
。
在当前的形式中,在block()
之后,您现在拥有ClientResponse
对象中有关响应的所有元数据(即来自响应标头),包括成功状态。这并不意味着响应主体已经完成。如果您不关心响应负载,您可以确认成功并保留它。
如果您还想查看响应正文,则需要将响应正文流转换为某个类。此时您可以决定是否要将所有内容读入单个 Mono
和 bodyToMono
或读入对象流 (Flux
) 和 bodyToFlux
,例如在响应是 JSON 数组的情况下可以解析成单独的独立 Java 对象。
但是,在您的情况下,您只想按原样查看 JSON。所以转换为String
就足够了。您只需使用bodyToMono
,它会返回一个Mono
对象。
WebClient webClient = WebClient.create();
String responseJson = webClient.get()
.uri("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.exchange()
.block()
.bodyToMono(String.class)
.block();
在这里,您使用block()
等待响应负载到达并被解析为String
,但您也可以将subscribe
发送到Mono
以在响应完成时接收它。
需要注意的一点是retrieve()
可以用来代替exchange()
来缩短ClientResponse
。在这种情况下,您让默认行为处理错误响应。使用exchange()
将所有责任放在应用程序上,以响应ClientResponse
上的错误响应。阅读更多in the Javadoc。 retrieve()
版本如下所示。无需block()
,因为您只关心响应数据。
WebClient webClient = WebClient.create();
String responseJson = webClient.get()
.uri("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.retrieve()
.bodyToMono(String.class)
.block();
【讨论】:
【参考方案2】:这是您向RestTemplate
提出请求的方式
String json = new RestTemplate()
.getForEntity("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.getBody();
这是您向requests
提出请求的方式
import requests
json = requests.get("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.content
这里是您向WebClient
提出请求的方式
String json = WebClient.create()
.get()
.uri("https://petstore.swagger.io/v2/pet/findByStatus?status=available")
.exchange()
.block()
.bodyToMono(String.class)
.block();
【讨论】:
因为requests
是用没有类型系统的javascript 编写的,因此getForEntity
,requests
本身也是阻塞的,WebClient
默认情况下不是。您在RestTemplate
和request
之间的比较是公平的,因为它们都是阻止客户端。如果您希望进行公平的比较,您应该将WebClient
与返回Promise
的Fetch
或Axios
进行比较,您会注意到javascript 也很“丑陋”。您正在将苹果与法拉利进行比较。
因此,如果它们本质上是不同的类别/类型,那么为什么我读到的所有内容都说RestTemplate
正在被WebClient
弃用? @ThomasAndolf 为什么我们要摆脱 spring 阻塞客户端?
因为维护2个客户端没有意义,工作量翻倍,WebClient可以充当RestTemplate,而RestTemplate不能充当WebClient
另外,不需要调用两次block,第一次可以去掉。以上是关于Spring5之WebClient简单使用的主要内容,如果未能解决你的问题,请参考以下文章
我可以使用从 Spring5 的 WebClient 返回的 Flux 的 block() 方法吗?