如何从 Spring WebClient 获取响应 json
Posted
技术标签:
【中文标题】如何从 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,第一次可以去掉。以上是关于如何从 Spring WebClient 获取响应 json的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring Boot WebClient 收集分页 API 响应?
Spring WebClient - 如何在 HTTP 错误(4xx、5xx)的情况下访问响应正文?
如何在 Spring 响应式 WebClient 中返回 Kotlin Coroutines Flow