Spring Boot 中基于 WebClient 的 SSE 流式接口实战

—— 从 Feign 到 WebClient 的一次真实踩坑记录

一、背景:为什么我要做 SSE?

在最近的一个项目中,我负责接入一个 AI 问答服务
一开始的接口形态非常常规:

@PostMapping("/health_manager") public RespBean<HealthManagerQueryDataVO> sendQuery(...) 

客户端发请求,服务端等 AI 全部生成完内容,再一次性返回。

问题很快就暴露了:

  • AI 返回慢(10 秒甚至更久)
  • 用户页面“卡死”,体验极差
  • 其实 AI 是“边生成边返回”的,但我们完全浪费了这个能力

于是,目标就很明确了:

把原有同步接口,改造成支持 SSE(Server-Sent Events)的流式接口

二、什么是 SSE?为什么适合 AI 问答?

1️⃣ SSE 是什么?

SSE(Server-Sent Events)是一种 服务器主动推送 的 HTTP 通信方式:

  • 基于 HTTP
  • 单向(服务端 → 客户端)
  • 长连接
  • 文本流(text/event-stream

返回的数据长这样:

data: 你好 data: 我是 data: AI 

客户端可以一边接收,一边渲染


2️⃣ 为什么 SSE 特别适合 AI 场景?

技术适配度
HTTP 普通接口❌ 等全部生成
WebSocket❌ 太重
SSE✅ 天生流式

AI 的输出特征是:

  • token 级 / 句子级生成
  • 可边生成边消费
  • 用户随时可能中断

👉 SSE 几乎是最优解


三、第一个坑:Feign 不支持 SSE

项目里原本调用 AI 服务用的是 Feign

@FeignClient("mb-ai") RespBean sendQuery(...) 

一开始我尝试“硬改”,但很快发现:

Feign 本质是一次性 HTTP 调用,它不支持流式消费响应体

哪怕 AI 服务是 SSE,Feign 也会:

  • 等完整响应
  • 再反序列化
  • 流式直接失效

结论很明确:

❌ Feign 不能用于 SSE
✅ SSE 必须用 WebClient / HttpClient

四、正确姿势:WebClient + SseEmitter

1️⃣ Controller 层:返回 SseEmitter

SSE 接口和普通接口最大的不同是:
返回值不再是业务对象,而是一个“连接本身”

@PostMapping( value = "/health_manager/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE ) public SseEmitter healthManagerStream( @RequestBody HealthManagerQueryDTO request) { SseEmitter emitter = new SseEmitter(0L); // 不超时 aiService.streamQuery(request, emitter); return emitter; } 

关键点:

  • produces = text/event-stream
  • 返回 SseEmitter
  • 业务逻辑交给 Service

2️⃣ Service 层:WebClient 真正消费 AI 流

webClient.post() .uri("/health_manager") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.TEXT_EVENT_STREAM) .bodyValue(request) .retrieve() .bodyToFlux(String.class) .subscribe( data -> emitter.send(data), error -> emitter.completeWithError(error), emitter::complete ); 

这段代码的含义是:

  • AI 每吐一段数据
  • 我就 emitter.send()
  • 前端立刻收到

真正实现了“边生成、边返回、边渲染”


五、第二个大坑:UnknownHostException: mb-ai

代码写完,一跑,直接报错:

java.net.UnknownHostException: mb-ai 

第一反应:

“不对啊,Feign 一直是能调用 mb-ai 的”

原因分析

  • Feign:自动走注册中心(Nacos / Eureka)
  • WebClient:只认 DNS
.baseUrl("http://mb-ai") 

在 WebClient 看来:

mb-ai 就是一个普通域名
但 DNS 根本不认识它

六、正确解法:WebClient 接入服务发现

1️⃣ 引入 LoadBalancer

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> 

2️⃣ 给 WebClient.Builder 加 @LoadBalanced

@Configuration public class WebClientConfig { @Bean @LoadBalanced public WebClient.Builder webClientBuilder() { return WebClient.builder(); } } 

3️⃣ baseUrl 继续用服务名

.baseUrl("http://mb-ai") 

此时调用链变成:

WebClient → LoadBalancer → Nacos → 真实 IP:PORT 

UnknownHostException 到此彻底解决


七、最终依赖组合(最小可用)

<!-- WebClient / SSE --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- 服务发现 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <!-- Nacos(项目里一般已有) --> spring-cloud-starter-alibaba-nacos-discovery 
⚠️ 不会把项目变成 WebFlux
只是“在 MVC 项目里用 WebClient”

八、架构上的最终形态(我现在的做法)

Feign └── 普通同步接口(兼容老系统) WebClient └── SSE 流式接口(AI 问答) 

接口层设计成:

POST /health_manager // 非流式 POST /health_manager/stream // SSE 

前端可以按需选择。


九、一些实战踩坑总结

❌ Feign 强行做 SSE

→ 行不通

❌ WebClient 不加 LoadBalanced

→ 必炸 UnknownHostException

❌ 忘了 produces

→ 前端收不到流

❌ AI 实际没返回 text/event-stream

→ 你这边再对也没用


十、写在最后

这次改造最大的收获不是“把 SSE 跑通了”,而是更清楚地理解了:

  • Feign 和 WebClient 的边界
  • 同步接口和流式接口在架构层面的本质差异
  • AI 场景对交互模型的倒逼

如果你现在也在做:

  • AI 问答
  • 长文本生成
  • 实时推送

那么,SSE 几乎是绕不开的一步

Read more

华为云Flexus+DeepSeek征文|云智融合·构建AI开发创新引擎·Web Search工作流搭建2.0版本的DeepSeek:简易浏览器

华为云Flexus+DeepSeek征文|云智融合·构建AI开发创新引擎·Web Search工作流搭建2.0版本的DeepSeek:简易浏览器

前引:“当前,数字经济蓬勃发展,云计算已成为承载万物智能的坚实底座,而人工智能则以前所未有的速度渗透并重塑着千行百业。在这场深刻的技术变革浪潮中,华为云始终走在前沿,以其领先的技术实力和前瞻性的战略布局,致力于为全球企业提供强大、可靠的云服务。特别是其在AI领域的持续深耕,催生了如DeepSeek和Dify等一系列创新平台。本文将深入探讨华为云如何凭借Dify高效的LLM应用开发框架和插件组合出独特的AI搜索【搭建一个简易浏览器】,共同构建AI开发新范式,加速智能化转型,解锁未来产业的无限可能 !怎么样,感兴趣了吗?! 目录 【一】云计算与人工智能在各行业中的核心地位 (1)云计算: (2)人工智能: 【二】华为云定位 (1)基础定位: (2)核心定位: (3)行业生态定位: 【三】本文核心 【四】华为云的整体框架 【五】华为云的服务体系 【六】华为云Flexus核心技术 【七】华为云Dify平台解析 (1)应用开发平台的特性 (2)核心优势 (3)华为云AI平台对比市场AI的优势

WebGIS视角:体感温度实证,哪座“火炉”火力全开?

WebGIS视角:体感温度实证,哪座“火炉”火力全开?

目录 前言 一、火炉城市空间分布及特点 1、空间分布 2、气候特点 二、数据来源及技术实现 1、数据来源介绍 2、技术路线简介 三、WebGIS系统实现 1、后端设计与实现 2、前端程序实现 四、成果展示 1、整体展示 2、蒸烤模式城市 3、舒适城市 五、总结 前言         “火炉城市”是中国对夏季天气酷热的城市的夸张称呼。这一说法最早出现在民国时期,当时媒体有“三大火炉”之说,即重庆、武汉和南京,都是长江沿线的著名大城市,分别居于长江的上、中、下游,因夏季气温炎热,被媒体夸张地称为“火炉”。新中国成立后,又有了“四大火炉”之说,

noteDigger:终极前端扒谱工具,让音乐制作变得简单快速

noteDigger:终极前端扒谱工具,让音乐制作变得简单快速 【免费下载链接】noteDigger在线前端频率分析扒谱 front-end music transcription 项目地址: https://gitcode.com/gh_mirrors/no/noteDigger noteDigger是一款创新的前端扒谱工具,专为音乐创作者和制作人设计。这款免费工具采用纯前端技术,无需安装任何软件或依赖库,双击即可使用,让音乐扒谱变得前所未有的简单!🎵 为什么选择noteDigger进行音乐扒谱? 在数字音乐时代,扒谱工具是每位音乐制作人的必备利器。noteDigger以其独特的优势脱颖而出: * 零配置使用:直接打开HTML文件即可开始工作 * 现代UI设计:直观的界面让新手也能快速上手 * 自主技术栈:完全自主研发,不依赖任何框架,项目体积小巧 * 跨平台兼容:支持所有现代浏览器,包括Chrome、Firefox等 快速上手:三步完成音乐扒谱 第一步:导入音频文件 noteDigger支持多种音频格式,包括常见的MP3、WAV文件,甚至视频格式如MP

速通前端篇 —— CSS

速通前端篇 —— CSS

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程程(ಥ_ಥ)-ZEEKLOG博客 所属专栏:速通前端 目录 CSS的介绍 基本语法规范 CSS选择器 标签选择器 class选择器  id选择器  复合选择器  通配符选择器 CSS常见样式  颜色 color 字体大小 font-size  边框 border  宽度 与 高度  内边距 外边距  CSS的介绍 CSS(Cascading Style Sheet),层叠样式表,用于控制页面的样式。CSS能够对网页中元素位置的排版进行像素级精确控制,实现美化页面的效果。能够做到页面的样式和结构分离。简单理解,CSS就是类似于对页面进行"化妆",让页面变得更加好看。 基本语法规范 选择器+{一条/N条声明} 1、