文章目录
- [WebSocket 和 SSE 简单使用及区别](#WebSocket 和 SSE 简单使用及区别)
-
- [1. SSE 是什么](#1. SSE 是什么)
- [2. Spring Boot 中使用 SSE](#2. Spring Boot 中使用 SSE)
- [3. SSE 适合哪些场景](#3. SSE 适合哪些场景)
- [4. WebSocket 是什么](#4. WebSocket 是什么)
- [5. Spring Boot 中使用 WebSocket](#5. Spring Boot 中使用 WebSocket)
- [6. WebSocket 适合哪些场景](#6. WebSocket 适合哪些场景)
- [7. WebSocket 和 SSE 的区别](#7. WebSocket 和 SSE 的区别)
- [8. 怎么选择](#8. 怎么选择)
- [9. 和 AI 流式输出的关系](#9. 和 AI 流式输出的关系)
- [10. 总结](#10. 总结)
WebSocket 和 SSE 简单使用及区别
在 Web 开发中,HTTP 请求通常是"一问一答":客户端发起请求,服务端返回响应,请求就结束了。
但有些场景需要服务端主动把数据推给客户端,例如:
- AI 流式回答
- 消息通知
- 聊天室
- 实时日志
- 订单状态变化
- 大屏数据刷新
这类场景常见的方案有两个:WebSocket 和 SSE。
1. SSE 是什么
SSE 全称是 Server-Sent Events,意思是服务端发送事件。
它的特点是:客户端通过 HTTP 建立连接,服务端可以持续向客户端推送文本数据。
SSE 是单向通信:
text
客户端 ----建立连接----> 服务端
客户端 <---持续推送---- 服务端
也就是说,SSE 主要适合"服务端不断推消息给客户端"的场景。
2. Spring Boot 中使用 SSE
Spring MVC 中可以使用 SseEmitter 实现 SSE。
java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@RestController
public class SseController {
@GetMapping("/sse")
public SseEmitter sse() {
SseEmitter emitter = new SseEmitter(0L);
new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
emitter.send("第 " + i + " 条消息");
Thread.sleep(1000);
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
}).start();
return emitter;
}
}
前端可以这样接收:
html
<!DOCTYPE html>
<html>
<body>
<div id="message"></div>
<script>
const eventSource = new EventSource("/sse");
eventSource.onmessage = function (event) {
const div = document.getElementById("message");
div.innerHTML += `<p>${event.data}</p>`;
};
eventSource.onerror = function () {
eventSource.close();
};
</script>
</body>
</html>
访问页面后,服务端会每隔一秒推送一条消息。
3. SSE 适合哪些场景
SSE 适合服务端向客户端单向推送数据:
- AI 流式输出
- 系统通知
- 实时日志
- 股票行情
- 订单状态推送
- 后台任务进度
比如 Spring AI 的流式输出,本质上就很适合配合 SSE 使用。服务端一边从大模型拿到生成内容,一边推给浏览器。
4. WebSocket 是什么
WebSocket 是一种双向通信协议。
建立连接后,客户端和服务端都可以主动给对方发消息。
text
客户端 <----双向通信----> 服务端
WebSocket 更像是一条长期存在的通信通道,适合实时互动场景。
5. Spring Boot 中使用 WebSocket
先定义 WebSocket 处理器:
java
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
session.sendMessage(new TextMessage("服务端收到:" + payload));
}
}
再配置 WebSocket 路径:
java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final MyWebSocketHandler myWebSocketHandler;
public WebSocketConfig(MyWebSocketHandler myWebSocketHandler) {
this.myWebSocketHandler = myWebSocketHandler;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/ws")
.setAllowedOrigins("*");
}
}
前端连接 WebSocket:
html
<!DOCTYPE html>
<html>
<body>
<input id="text" placeholder="请输入消息">
<button onclick="send()">发送</button>
<div id="message"></div>
<script>
const socket = new WebSocket("ws://localhost:8080/ws");
socket.onmessage = function (event) {
const div = document.getElementById("message");
div.innerHTML += `<p>${event.data}</p>`;
};
function send() {
const input = document.getElementById("text");
socket.send(input.value);
input.value = "";
}
</script>
</body>
</html>
这样客户端可以主动发送消息给服务端,服务端也可以主动返回消息。
6. WebSocket 适合哪些场景
WebSocket 适合双向实时通信:
- 在线聊天室
- 在线客服
- 多人协作编辑
- 实时游戏
- 实时控制台
- 需要客户端和服务端频繁互发消息的业务
如果业务只是服务端推送进度或模型输出,用 SSE 更简单。如果业务需要用户和服务端实时互发消息,用 WebSocket 更合适。
7. WebSocket 和 SSE 的区别
| 对比项 | SSE | WebSocket |
|---|---|---|
| 通信方向 | 服务端到客户端,单向推送 | 客户端和服务端双向通信 |
| 协议 | 基于 HTTP | 独立的 WebSocket 协议 |
| 前端 API | EventSource |
WebSocket |
| 数据格式 | 主要是文本 | 文本和二进制都可以 |
| 自动重连 | 浏览器原生支持 | 需要自己实现 |
| 使用复杂度 | 较简单 | 相对复杂 |
| 适合场景 | 通知、日志、进度、AI 流式输出 | 聊天、协作、游戏、实时交互 |
| 浏览器支持 | 主流浏览器支持 | 主流浏览器支持 |
8. 怎么选择
如果只是服务端持续推送数据,优先考虑 SSE。
例如:
text
服务端生成内容 -> 浏览器实时展示
这类场景使用 SSE 更简单。
如果客户端和服务端都需要频繁主动发送消息,选择 WebSocket。
例如:
text
用户发送消息 -> 服务端处理 -> 服务端推送给其他用户
这类场景 WebSocket 更合适。
简单总结:
text
只需要服务端推客户端:SSE
需要客户端和服务端双向通信:WebSocket
9. 和 AI 流式输出的关系
在 AI 应用中,用户输入一个问题后,大模型通常会一点一点生成内容。
这时常见流程是:
text
用户提问
↓
后端调用大模型 stream 接口
↓
后端收到一段内容
↓
通过 SSE 推给前端
↓
前端逐字或逐段展示
如果使用 Spring AI,后端可能会返回 Flux<String>:
java
@GetMapping(value = "/ai/stream", produces = "text/html;charset=UTF-8")
public Flux<String> stream(String msg) {
return chatClient.prompt()
.user(msg)
.stream()
.content();
}
这种写法就非常适合配合前端流式展示。
如果是完整的 AI 聊天室,而且需要用户在线状态、多人消息广播、主动取消生成、服务端主动控制会话等复杂能力,可以考虑 WebSocket。
10. 总结
SSE 和 WebSocket 都可以实现实时通信,但定位不一样。
SSE 更轻量,适合服务端单向推送,例如通知、进度、日志、AI 流式输出。
WebSocket 更灵活,适合双向通信,例如聊天室、在线客服、协作编辑、实时游戏。
实际开发中,不需要一上来就用最复杂的方案。能用普通 HTTP 解决就用 HTTP;需要服务端推送就考虑 SSE;需要双向实时通信再使用 WebSocket。