一、什么是SSE?
SSE(Server-Sent Events)是一种服务器向客户端推送数据的技术,它允许服务器主动向客户端发送数据,而不需要客户端频繁轮询。SSE特别适合实时通信场景,比如AI聊天的流式输出、实时通知、股票行情更新等。
SSE的核心特点:
- 单向通信 :服务器向客户端单向推送数据
- 基于HTTP :使用标准的HTTP协议,不需要特殊的服务器支持
- 自动重连 :连接断开时会自动尝试重连
- 文本格式 :使用简单的文本格式传输数据
- 轻量级 :实现简单,开销小
一、什么是SSE? SSE(Server-Sent Events)是一种服务器向客户端推送数据的技术,它允许服务器主动向客户端发送数据,而不需要客户端频繁轮询。SSE特别适合实时通信场景,比如**AI聊天的流式输出**、实时通知、股票行情更新等。 SSE的核心特点: 单向通信 :服务器向客户端单向推送数据 基于HTTP :使用标准的HTTP协议,不需要特殊的服务器支持 自动重连 :连接断开时会自动…
SSE(Server-Sent Events)是一种服务器向客户端推送数据的技术,它允许服务器主动向客户端发送数据,而不需要客户端频繁轮询。SSE特别适合实时通信场景,比如AI聊天的流式输出、实时通知、股票行情更新等。
客户端通过向服务器发送一个HTTP请求来建立SSE连接。服务器返回一个特殊的响应,设置 Content-Type: text/event-stream 头,告诉客户端这是一个SSE流。
服务器以流的形式持续发送数据,每个数据块都是一个SSE格式的消息。SSE消息格式如下:
data: 消息内容\n\n
其中:
客户端接收并解析流式数据,根据消息内容进行相应处理。在浏览器中,可以使用 EventSource API 或 fetch + ReadableStream 来处理SSE。
EventSource 是浏览器内置的SSE客户端API,使用非常简单:
const sse =newEventSource('/api/ stream'); sse.addEventListener('message',(event)=>{const data =JSON.parse(event. data); console.log('收到数据:', data);}); sse.addEventListener('error',(event)=>{ console.error('SSE错误:', event);});
注意 : EventSource 只支持GET请求,无法发送POST数据。
当需要向服务器发送POST数据时(比如发送用户输入到AI模型),可以使用 fetch + ReadableStream 来模拟SSE:
const response =awaitfetch('/api/ stream-chat',{method:'POST',headers:{'Content-Type': 'application/ json',},body:JSON.stringify({userInput: inputText })});if(!response.ok)thrownewError(`HTTP 错误:${response.status}`);if(!response.body)thrownewError("响应体不可用");const reader = response.body.getReader();const decoder =newTextDecoder();let buffer ='';while(true){const{ done, value }=await reader.read();if(done)break; buffer += decoder.decode(value,{stream:true});const lines = buffer.split('\n\n'); buffer = lines.pop()||'';for(const line of lines){if(!line.startsWith('data: '))continue;const dataStr = line.slice(6);const data =JSON.parse(dataStr);// 处理数据...}}
app.post('/api/stream-chat',async(req, res)=>{try{const{ userInput }= req.body;if(!userInput)return res.status(400).json({error: "用户 输入不能为空" });// 设置 SSE 响应头 res.setHeader('Content-Type','text/event-stream'); res.setHeader('Cache-Control','no-cache'); res.setHeader('Connection','keep-alive');// 立即发送响应头 res.flushHeaders();// 调用 AI 模型生成回复const stream =await model.stream(`用户提问:${userInput}, 请用简洁的语言回复`);// 逐块发送 AI 输出forawait(const chunk of stream){ res.write(`data: ${JSON.stringify({content: chunk?. content || chunk })}\n\n`);}// 发送结束标识 res.write(`data: ${JSON.stringify({done:true})} \n\n`); res.end();}catch(err){ console.error('Error in stream-chat:', err); res.write(`data: ${JSON.stringify({error: err?. message ||'服务器内部错误'})} \n\n`); res.end();}});
// 发送请求const response =awaitfetch('http://localhost:8000/api/ stream-chat',{method:'POST',headers:{'Content-Type': 'application/ json',},body:JSON.stringify({userInput: inputText })});// 检查响应if(!response.ok)thrownewError(`HTTP 错误:${response.status}`);if(!response.body)thrownewError("响应体不可用");// 创建读取器和解码器const reader = response.body.getReader();const decoder =newTextDecoder();let buffer ='';// 处理流式数据while(isStreaming){const{ done, value }=await reader.read();if(done)break;// 解码并处理 SSE 格式数据 buffer += decoder.decode(value,{stream:true});const lines = buffer.split('\n\n'); buffer = lines.pop()||'';// 处理每一条消息for(const line of lines){if(!line.startsWith('data: '))continue;const dataStr = line.slice(6);const data =JSON.parse(dataStr);// 处理错误信息if(data.error){ aiMsgElement.textContent =` 错误:${data.error}`; isStreaming =false;break;}// 处理结束标识if(data.done){ isStreaming =false;break;}// 逐字显示 AI 回复 aiMsgElement.textContent += data.content;}}
SSE使用简单的文本格式,每个消息以 data: 开头,以 \n\n 结束。前端需要:
使用 ReadableStream API 读取流式数据:
使用 TextDecoder API 将二进制数据转换为字符串:
需要处理多种错误情况:
需要管理流式处理的状态:
特性 SSE WebSocket 通信方向 单向(服务器→客户端) 双向 协议 HTTP WebSocket 实现复杂度 低 高 自动重连 支持 需手动实现 数据格式 文本(通常JSON) 二进制或文本 跨域支持 支持(CORS) 需特殊配置 适用场景 实时通知、流式输出 实时聊天、游戏
SSE特别适合以下场景:
try{// 现有代码...}catch(error){// 显示错误信息 aiMsgElement.textContent +=`\n (出错:${error.message})`;// 在控制台输出错误 console.error("流式接收错误:", error);// 重置状态 isStreaming =false; sendBtn.disabled =false; stopBtn.style.display ='none';}
// 对于大型消息,使用DocumentFragment 减少DOM操作 const fragment = document.createDocumentFragment();const tempElement = document.createElement('div');// 处理数据时先更新临时元素 tempElement.textContent += data. content;// 定期更新DOM(比如每100ms)if(Date.now()- lastUpdateTime >100){ aiMsgElement.textContent = tempElement.textContent; lastUpdateTime = Date.now();}
// 添加加载动画 aiMsgElement.innerHTML = '<div class="loading">生成中...</div>';// 流式结束后移除加载动画if(data.done){ aiMsgElement.innerHTML = aiMsgElement.textContent; isStreaming =false;break;}
SSE是一种简单高效的服务器向客户端推送数据的技术,特别适合实时流式输出场景。通过本文的介绍,你应该已经了解了:
希望本文对你理解和实现SSE有所帮助!

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online