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

Spring WebClient请求无数据返回 SSE流式转发无响应问题排查

问题场景

基于Spring Boot框架开发,需要实现将上游Web服务的数据流重定向转发至浏览器端,初始服务端实现代码如下:

public Flux<String> getDataStream(String configType, String configId, String user){
    Flux<String> response = null;
    Optional<String> url = getLogURL(configId);
    if(url.isPresent()){
      logger.info("#WebClient initiation");
      WebClient webClient = WebClient.create();
      response = webClient.get()
         .uri(url.get())
         .accept(MediaType.ALL)
         .retrieve()
         .bodyToFlux(String.class);
    }
    logger.info("#WebClient response");
    return response;
}

前端通过EventSource对接该流接口,调用代码如下:

let eventSource = new EventSource(STREAM_URL);

请求发起后,服务端日志可以正常打印#WebClient initiation和#WebClient response两条记录,且已确认getDataStream()方法中WebClient请求的上游目标URL本身可正常持续输出内容,但客户端始终无法收到任何响应数据。

相关参考截图:
请求Content-Type截图
运行情况截图

故障原因

问题核心是SSE(Server-Sent Events)长流的响应配置缺失,具体有三点:

  • 接口未声明响应类型为text/event-stream,Spring WebFlux默认会对返回值做全量缓冲,等到Flux流完全结束后才会把所有数据一次性返回给客户端,而日志类长流不会主动结束,因此客户端一直拿不到数据
  • WebClient拉取上游流时未指定匹配SSE的接收类型,且直接返回Flux<String>会默认按字符串拆分逻辑切割流内容,可能破坏SSE的消息格式规范
  • 未关闭链路中的响应缓冲(包括Spring层、反向代理/网关层),缓冲机制会攒够一定大小的数据包才会向下游发送,无法实现实时推送
修复方案
  1. 给接口添加正确的响应类型声明,返回标准SSE格式的响应,参考实现:
// 接口注解必须指定produces为SSE类型
@GetMapping(value = "/your-stream-path", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> getDataStream(String configType, String configId, String user){
    Optional<String> targetUrl = getLogURL(configId);
    if(targetUrl.isEmpty()){
        return Flux.just(ServerSentEvent.<String>builder()
                .event("error")
                .data("上游流地址不存在")
                .build());
    }
    WebClient webClient = WebClient.create();
    return webClient.get()
            .uri(targetUrl.get())
            .accept(MediaType.TEXT_EVENT_STREAM)
            .retrieve()
            .bodyToFlux(String.class)
            .map(content -> ServerSentEvent.builder(content).build());
}
  1. 如果不需要SSE的自定义事件格式,仅需要逐块推送原始文本流,可以直接返回DataBuffer类型避免Spring层缓冲:
@GetMapping(value = "/your-stream-path", produces = MediaType.TEXT_PLAIN_VALUE)
public Flux<DataBuffer> getDataStream(String configType, String configId, String user){
    Optional<String> targetUrl = getLogURL(configId);
    if(targetUrl.isEmpty()){
        return Flux.empty();
    }
    WebClient webClient = WebClient.create();
    return webClient.get()
            .uri(targetUrl.get())
            .accept(MediaType.ALL)
            .retrieve()
            .bodyToFlux(DataBuffer.class);
}
  1. 链路配置检查:
  • 关闭Spring Boot的HTTP响应压缩配置,响应压缩会强制缓冲全量内容再输出
  • 如果服务前端部署了Nginx、API网关等代理层,需要关闭对应路径的代理缓冲,以Nginx为例需要添加配置proxy_buffering off;

内容的提问来源于stack exchange,提问作者p zankat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:31:05