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本身可正常持续输出内容,但客户端始终无法收到任何响应数据。
相关参考截图:

故障原因
问题核心是SSE(Server-Sent Events)长流的响应配置缺失,具体有三点:
- 接口未声明响应类型为
text/event-stream,Spring WebFlux默认会对返回值做全量缓冲,等到Flux流完全结束后才会把所有数据一次性返回给客户端,而日志类长流不会主动结束,因此客户端一直拿不到数据 - WebClient拉取上游流时未指定匹配SSE的接收类型,且直接返回
Flux<String>会默认按字符串拆分逻辑切割流内容,可能破坏SSE的消息格式规范 - 未关闭链路中的响应缓冲(包括Spring层、反向代理/网关层),缓冲机制会攒够一定大小的数据包才会向下游发送,无法实现实时推送
修复方案
- 给接口添加正确的响应类型声明,返回标准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()); }
- 如果不需要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); }
- 链路配置检查:
- 关闭Spring Boot的HTTP响应压缩配置,响应压缩会强制缓冲全量内容再输出
- 如果服务前端部署了Nginx、API网关等代理层,需要关闭对应路径的代理缓冲,以Nginx为例需要添加配置
proxy_buffering off;
内容的提问来源于stack exchange,提问作者p zankat
相关产品推荐
相关产品推荐

