全称Server Send Events: 是 HTML5 标准中定义的一种基于 HTTP 的服务器向客户端单向推送实时数据的协议。其核心特性包括:
- 单向通信:服务器主动推送数据至客户端,客户端无需轮询;
- 自动重连:连接中断后客户端自动尝试恢复;
- 文本流式传输:数据格式为
text/event-stream,支持纯文本消息; - 事件类型支持:可自定义事件名称(如
event: update)。
经典的 HTTP 请求: 前端发一个请求,Tomcat 里的线程去查 MySQL、查 Redis,组装好一个 JSON,然后 return。
- 特点:一问一答,过河拆桥。回答完立刻断开连接。
- 痛点:如果后端处理要花 20 秒,前端就得干等 20 秒,页面看着像死机了一样。
轮询 Polling: 解决干等,前端写定时器,每隔一段时间请求一次后端。
- 痛点:太浪费服务器资源了!你的 Nginx 和 Tomcat 会被这种无意义的重复请求直接打死。
WebSocket: 双向的高级通道。前端和后端接通后,双方可以随时互相发消息。
- 特点:全双工,适合做多人在线聊天室、对战小游戏。
- 痛点:太重了,它是一个全新的协议,Nginx 还需要专门去配置协议升级,而且维护长连接对服务器端资源消耗很大。
SSE 依然是普通的 HTTP 请求,唯一不同的是,正常的 HTTP 响应头里写的是 Content-Type: application/json;而 SSE 的响应头是 Content-Type: text/event-stream。
适用范围: 
示例: 实现打字机效果
后端:写一个普通的 Controller,但返回类型必须是 SseEmitter
java
@RestController
@RequestMapping("/api")
@CrossOrigin
public class SseDemoController {
@GetMapping(value = "/stream", produces = "text/event-stream;charset=UTF-8")
public SseEmitter stream(){
//1.建立连接,0L表示永不过时
SseEmitter emitter=new SseEmitter(0L);
//2.模拟大模型思考与吐字的过程,不能阻塞主线程
new Thread(()->{
try {
String[] words={"你","好",",","这","里","是","教","程","实","例"};
for(String word:words){
Thread.sleep(500);
emitter.send(word);
}
//3.数据发送完毕,告诉前端关掉水管
emitter.complete();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (IOException e) {
//发生异常,通知前端出错了
emitter.completeWithError(e);
}
}).start();
//4.立即把水管返回给前端
return emitter;
}
}前端:浏览器原生的 EventSource 对象就是专门用来接收 SSE 的
html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>SSE 打字机测试</title>
<style> #chat-box {
width: 400px;
height: 200px;
border: 2px solid #333;
padding: 10px;
font-size: 20px;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h2>AI 回答区:</h2>
<div id="chat-box"></div>
<button onclick="startChat()">问一下大模型</button>
<script>
function startChat() {
const chatBox = document.getElementById('chat-box');
chatBox.innerText = ''; // 清空历史记录
// 1. 拨通后端的 SSE 接口
// 替换成Spring Boot真实的启动端口
const eventSource = new EventSource('http://localhost:8081/api/stream');
// 2. 监听消息:后端只要调用 emitter.send(),这里就会被触发
eventSource.onmessage = function(event) {
// event.data 就是后端传过来的那个字
chatBox.innerText += event.data;
};
// 3. 监听结束/错误:后端调用 emitter.complete() 时触发
eventSource.onerror = function(event) {
console.log("数据接收完毕或发生异常,断开连接");
// 极其重要:SSE 默认有断线重连机制,必须手动 close 才能真正掐断
eventSource.close();
};
}
</script>
</body>
</html>