You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring WebFlux中WebClient处理延迟Flux的差异行为咨询

Spring WebFlux Flux响应行为差异解析

问题场景回顾

定义了两个Flux端点:

  • /customObjectsAsString:返回Flux<String>,每个元素延迟3秒发射
  • /customObjects:返回Flux<CustomObject>,每个元素延迟3秒发射

测试发现:

  • Chrome访问/customObjectsAsString时,每隔3秒依次显示字符串;访问/customObjects时,等待6秒后一次性显示完整JSON数组
  • WebClient测试中,两个接口均需等待6秒后一次性接收所有元素

1. 字符串形式与JSON形式发射元素的差异

核心差异在于媒体类型和序列化逻辑:

  • 字符串Flux:默认使用text/plain媒体类型,Spring WebFlux会将每个String元素作为独立文本块逐块发送,无需额外结构包裹,每个元素可单独被识别。
  • 自定义对象Flux:默认使用application/json媒体类型,Jackson序列化器会把整个Flux序列化为标准JSON数组(格式[{}, {}])。由于JSON数组必须以]闭合才是有效格式,服务端需等待所有元素生成完毕才能完成序列化,因此一次性返回全部数据。

若要让自定义对象也能逐元素发送,需启用JSON流模式,指定媒体类型为application/stream+json,此时每个对象会被单独序列化,以换行分隔,而非包裹在数组中。

2. WebClient无法逐元素接收的原因及解决方法

WebClient的行为由响应媒体类型和消息转换器的处理逻辑决定:

  • 对于/customObjects(JSON数组):bodyToFlux(CustomObject.class)依赖Jackson解析完整JSON数组,只有当整个数组接收完成后,才能拆分出多个CustomObject实例,因此一次性返回所有元素。
  • 对于/customObjectsAsString(纯文本):默认的text/plain消息转换器会把整个响应体拼接成一个String后再发射给Flux,而非逐块拆分。

解决代码示例

修改自定义对象接口为JSON流模式

import org.springframework.http.MediaType;

@GetMapping(value="/customObjects", produces = MediaType.APPLICATION_STREAM_JSON_VALUE)
public Flux<CustomObject> getCustomObjects() {
    CustomObject customObjectOne = CustomObject.builder().text("One").number(1).build();
    CustomObject customObjectTwo = CustomObject.builder().text("Two").number(2).build();
    return Flux.just(customObjectOne, customObjectTwo).delayElements(Duration.ofSeconds(3));
}

修改WebClient字符串接口请求为事件流模式

Flux<String> flux = WebClient.builder().baseUrl("http://localhost:8080").build().get()
        .uri("/customObjectsAsString")
        .accept(MediaType.TEXT_EVENT_STREAM)
        .retrieve().bodyToFlux(String.class);

修改后,WebClient就能每隔3秒接收一个元素,日志会显示不同的时间戳。

3. 浏览器表现差异的原因

浏览器对不同媒体类型的响应处理逻辑不同:

  • /customObjectsAsString(text/plain):浏览器会实时渲染接收到的文本内容,每收到一块新文本就追加显示在页面上,因此能看到每隔3秒出现新内容。
  • /customObjects(application/json):浏览器会等待完整的有效JSON结构(闭合的数组)加载完成后,才会显示格式化的JSON内容。如果改为application/stream+json,浏览器会接收到换行分隔的JSON对象,但默认不会自动逐行解析显示,需要前端JavaScript通过ReadableStream处理流数据才能实现实时展示。

内容的提问来源于stack exchange,提问作者harish ch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:27:50