[字节青训_AI对话框]SSE交互规范、自定义事件、前后端数据传递、状态监听、连接和断开详解
1.SSE基础
以下是关于 Server-Sent Events (SSE) 的前后端交互规范、常见方法及自定义扩展的完整指南:
一、SSE 交互规范
1. 基础协议
- HTTP 协议:基于 HTTP/1.1
长连接
,响应头需包含:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
2. 数据格式规范
每条消息格式为:
[field]: value\n
支持字段:
data
:消息内容(必填)event
:自定义事件类型(默认message
)id
:消息ID(用于断线重连定位)retry
:重连时间(毫秒)
示例:标准数据流
event: status
{"progress": 75%}
This is a message\n
with two lines
id: 12345
retry: 5000
二、常见方法
1. 前端基础用法
const es = new EventSource('/api/stream');
// 监听默认事件
es.onmessage = ({
data }) => console.log('Received:', data);
// 监听自定义事件
es.addEventListener('update', ({
data }) => {
console.log('Update:', JSON.parse(data));
});
// 错误处理
es.onerror = () => console.error('Connection lost');
2. 后端基础实现(Node.js)
app.get('/api/stream', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*' // 处理跨域
});
// 发送初始数据
res.write('Connected\n\n');
// 定时推送数据
const timer = setInterval(() => {
res.write(`${
Date.now()}\n\n`);
}, 1000);
// 客户端断开时清理
req.on('close', () => clearInterval(timer));
});
三、自定义扩展方法
1. 身份验证
- 前端:通过 URL 参数或 Cookie 传递 Token
new EventSource('/api/stream?token=xxxx')
- 后端:验证 Token 有效性
app.get('/api/stream', (req, res) => {
if (!validateToken(req.query.token)) {
res.writeHead(401).end();
return;
}
// ...后续推送逻辑
});
2. 结构化数据传递
使用 JSON 编码:
// 前端解析
es.onmessage = ({
data }) => {
const msg = JSON.parse(data);
console.log(msg.type, msg.content);
};
// 后端发送
res.write(`data:${
JSON.stringify({
type: 'alert', content: 'Warning' })}\n\n`);
3. 分块传输大文本(流式数据处理)
// 后端分块发送
const bigText = "Very long text...";
for (const chunk of chunkText(bigText, 100)) {
// 每100字符分块
res.write(`event: chunk\n${
chunk}\n\n`);
}
// 前端组装
let fullText = '';
es.addEventListener('chunk', ({
data }) => {
fullText += data;
});
4. 双向通信模拟
SSE 是单向通道,但可通过以下方式模拟双向:
// 前端通过 AJAX 发送控制命令
function sendCommand(cmd) {
fetch('/api/control', {
method: 'POST', body: cmd });
}
// 后端响应命令并推送结果
app.post('/api/control', (req, res) => {
handleCommand(req.body, (result) => {
sseClients.forEach(client =>
client.res.write(`event: command-result\n${
result}\n\n`)
);
});
res.status(200).end();
});
四、高级实践
1. 性能优化
- 压缩数据:启用
gzip
压缩
app.use(compression()); // Express 中间件
- 心跳检测:防止代理超时(
核心,面试!!!
)
setInterval(() => res.write(': ping\n\n'), 30000);
3. 错误恢复
(重连,简历
)
let es = null;
function connectSSE() {
es = new EventSource('/api/stream');
es.onerror = () => {
es.close();
setTimeout(connectSSE, 5000); // 5秒后重连
};
}
connectSSE(); // 初始连接
五、注意事项
-
跨域问题
确保响应头包含Access-Control-Allow-Origin
,或通过代理解决。 -
连接限制
浏览器对单个域名 SSE 连接数有限制(通常 6 个),需合理设计连接复用。 -
数据安全
敏感数据需加密或通过 HTTPS 传输。 -
兼容性
SSE 不支持 IE
,需使用 Polyfill(如eventsource
库)。
通过上述规范和扩展方法,SSE 可灵活应用于实时监控、消息推送、日志流等场景。开发者应根据具体需求选择合适的数据格式和通信模式。
2.前端SSE类封装
//EventSourceWrapper.js
type EventSourceConfig = {
url: string;
queryParams?: Record<string, string>;
onMessage: (string) => void; // 直接传递数据
onError?: (error: Error) => void;
};
export class EventSourceWrapper {
private eventSource: EventSource | null = null;
constructor(private