概述在现代 Web 应用中实时数据推送已成为提升用户体验的关键需求。从新闻网站的实时更新、金融行情的动态展示到 AI 大模型逐字输出的“打字机”效果用户期望在不主动刷新页面的情况下即时获取最新数据。然而传统的 HTTP 协议基于请求-响应模式客户端必须主动发起请求才能获取新数据。这不仅导致高延迟还造成频繁轮询带来的资源浪费。Server-Sent EventsSSE服务器发送事件作为 HTML5 引入的一种轻量级、基于 HTTP 的单向通信技术成功地解决了这一痛点。一、SSE 基础概念1.1 什么是 SSESSEServer-Sent Events是一种基于 HTTP 协议的技术用于实现服务器向客户端的单向实时数据推送。它也被称为“事件流”Event Stream允许服务器在客户端请求保持打开的状态下持续推送更新。SSE 是 HTML5 规范的一部分主要由两部分组成服务端与浏览器的通讯协议基于 HTTP以及浏览器端可供 JavaScript 使用的 EventSource 对象。1.2 SSE 的核心特性SSE 具备以下几个核心特点特性说明单向通信数据只能从服务器流向客户端客户端无法通过 SSE 连接向服务器发送数据基于 HTTP 长连接通过 HTTP 协议建立连接后服务器保持连接持久化持续推送数据轻量级协议使用 text/event-stream 文本格式传输协议开销远低于 WebSocket自动重连机制浏览器内置断线重连逻辑可通过 retry 字段控制重连间隔事件驱动模型支持自定义事件类型客户端可针对不同事件分别处理1.3 SSE vs WebSocket vs 传统轮询理解 SSE 与其他通信方式的差异是做好技术选型的基础对比维度SSEWebSocket传统 HTTP轮询通信方向服务器 → 客户端单向服务器 ↔ 客户端双向客户端 → 服务器被动请求协议基础基于 HTTP基于 HTTP 升级WS/WSS基于 HTTP连接方式长连接长连接TCP短连接每次新建数据格式文本格式事件流二进制或文本帧完整 HTTP 响应体实时性高极高低依赖轮询间隔协议开销低中高自动重连原生支持需手动实现不适用选型建议如果业务场景只需要服务器向客户端推送数据如通知、行情、AI 流式输出SSE 是更简单、更轻量的选择如果需要频繁的双向交互如聊天、在线游戏则应选择 WebSocket。二、SSE 适用场景SSE 最适合服务器需要主动向客户端推送数据的场景2.1 AI 大模型流式响应大模型推理耗时久、输出长SSE 可以实现“边推理边输出”的流式效果。ChatGPT 等 AI 应用的逐字输出正是基于 SSE 技术实现。2.2 实时通知系统社交平台的好友消息、新动态推送电商平台的新订单提醒审核状态更新等。2.3 实时数据看板股票行情、汇率变动、设备监控数据、实时日志流等需要高频更新的数据展示场景。2.4 赛事与新闻直播体育比赛比分更新、赛事进程推送、突发新闻实时推送。2.5 文件下载进度大文件下载或生成过程中的进度实时反馈。SSE 适用场景的核心特征是数据更新频繁、对实时性有要求、仅需服务器单向推送。三、SSE 工作原理3.1 通信流程SSE 的工作流程可以概括为以下五个步骤客户端发起连接前端通过 EventSource 对象发起 HTTP GET 请求请求头携带 Accept: text/event-stream 标识流式需求。服务端建立长连接服务端设置响应头 Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-alive保持连接不关闭。流式数据推送服务端按 data: 内容\n\n 格式持续发送数据。前端实时解析前端监听 message 事件逐段接收并实时渲染数据。连接关闭数据传输完成时服务端发送结束标识或由任意一方主动关闭。3.2 消息格式SSE 的消息格式非常简洁event:userupdateid:12345data:{username:john_doe,status:online}关键字段说明data:实际的消息内容必需event:事件类型可选默认为 messageid:消息唯一标识用于断点续传retry:断线重连前的等待时间毫秒每条消息以两个换行符 \n\n 结尾。四、代码示例4.1 基础用法前端客户端浏览器原生提供了 EventSource API使用非常简单。检测浏览器兼容性if(EventSourceinwindow){console.log(浏览器支持 SSE);}else{console.log(浏览器不支持 SSE需降级处理);}创建连接与监听事件// 建立 SSE 连接consteventSourcenewEventSource(/api/sse/stream);// 连接建立成功eventSource.onopenfunction(event){console.log(SSE 连接已建立);};// 接收消息默认事件eventSource.onmessagefunction(event){constdataJSON.parse(event.data);console.log(收到数据,data);// 更新页面内容...};// 处理连接错误eventSource.onerrorfunction(event){console.error(SSE 连接出错);};// 监听自定义事件eventSource.addEventListener(notification,function(event){constdataJSON.parse(event.data);console.log(收到通知,data);});// 主动关闭连接// eventSource.close();跨域携带 CookieconstsourcenewEventSource(url,{withCredentials:true// 跨域请求携带 Cookie});4.2 场景一AI 大模型流式响应这是 SSE 目前最热门的应用场景之一。下面展示如何实现类似 ChatGPT 的“打字机”效果。后端示例Node.js Expressconstexpressrequire(express);constappexpress();app.get(/api/ai/stream,(req,res){// 设置 SSE 必需的响应头res.setHeader(Content-Type,text/event-stream);res.setHeader(Cache-Control,no-cache);res.setHeader(Connection,keep-alive);// 模拟 AI 逐字生成consttext你好欢迎使用 AI 助手;letindex0;constintervalsetInterval((){if(indextext.length){// 逐个字符推送res.write(data:${JSON.stringify({char:text[index],done:false})}\n\n);index;}else{// 发送结束标识res.write(data:${JSON.stringify({done:true})}\n\n);clearInterval(interval);res.end();}},100);// 客户端断开时清理资源req.on(close,(){clearInterval(interval);res.end();});});app.listen(3000);前端实现consteventSourcenewEventSource(/api/ai/stream);letoutput;eventSource.onmessagefunction(event){constdataJSON.parse(event.data);if(data.done){console.log(AI 回复完成);eventSource.close();return;}// 逐字追加实现打字机效果outputdata.char;document.getElementById(ai-output).textContentoutput;};eventSource.onerrorfunction(){console.error(AI 流式连接中断);};4.3 场景二文件下载进度推送大文件下载或生成时通过 SSE 实时推送进度信息。后端示例Node.jsapp.get(/api/download/progress,(req,res){res.setHeader(Content-Type,text/event-stream);res.setHeader(Cache-Control,no-cache);res.setHeader(Connection,keep-alive);letprogress0;constintervalsetInterval((){progressMath.random()*10;if(progress100){progress100;res.write(data:${JSON.stringify({progress,status:complete})}\n\n);clearInterval(interval);res.end();}else{res.write(data:${JSON.stringify({progress,status:downloading})}\n\n);}},500);req.on(close,(){clearInterval(interval);res.end();});});前端实现consteventSourcenewEventSource(/api/download/progress);constprogressBardocument.getElementById(progress-bar);conststatusTextdocument.getElementById(status-text);eventSource.onmessagefunction(event){constdataJSON.parse(event.data);// 更新进度条progressBar.style.widthdata.progress%;progressBar.textContentdata.progress%;if(data.statuscomplete){statusText.textContent✅ 下载完成;eventSource.close();// 触发实际文件下载...}else{statusText.textContent⏳ 下载中${Math.round(data.progress)}%;}};实践建议进度更新应进行节流throttle避免过于频繁地推送消息导致前端性能问题。五、最佳实践与注意事项5.1 连接稳定性保障心跳保活如果服务器超过约 30 秒没有数据推送建议发送心跳消息如 data: ping\n\n保持连接活跃避免被代理或网关超时断开。自动重连浏览器默认在连接断开后 3 秒自动重连可通过 retry 字段自定义间隔。断点续传利用 Last-Event-ID 机制客户端重连时可告知服务器上次收到的消息 ID实现断点续传。5.2 服务端配置要点// SSE 必需的响应头res.setHeader(Content-Type,text/event-stream);res.setHeader(Cache-Control,no-cache);res.setHeader(Connection,keep-alive);5.3 Nginx 反向代理注意事项使用 Nginx 代理 SSE 时务必禁用代理缓冲否则数据会被缓冲到一定大小才发送破坏实时性location /sse/ { proxy_pass http://backend; proxy_buffering off; proxy_cache off; proxy_set_header Connection ; proxy_http_version 1.1; chunked_transfer_encoding off; }5.4 连接数限制HTTP/1.1 下浏览器对同一域名有 6 个连接的限制。如果需要同时维持大量 SSE 连接建议使用 HTTP/2 或多域名部署。5.5 安全建议使用 HTTPS 加密通信对 SSE 端点进行身份验证设置合理的超时时间5.6 错误处理与降级监听 error 事件并实现指数退避重试策略letretryCount0;constmaxRetries5;functionconnectSSE(){constsourcenewEventSource(/api/sse);source.onerrorfunction(){source.close();if(retryCountmaxRetries){constdelayMath.min(1000*Math.pow(2,retryCount),30000);setTimeout((){retryCount;connectSSE();},delay);}};}六、总结SSEServer-Sent Events是一项成熟、轻量且易于实现的服务器推送技术。它的核心价值在于简单易用基于标准 HTTP 协议无需额外协议升级浏览器原生支持自动重连内置断线重连机制开箱即用生态兼容天然适配现有的 HTTP 基础设施代理、负载均衡、防火墙资源高效协议开销低单连接内存占用小在 AI 大模型流式响应、实时通知、数据看板等需要服务器单向推送的场景中SSE 往往是比 WebSocket 更务实的选择。它不像 WebSocket 那样功能强大但正因其“克制”才换来了简单、稳定和低门槛——而这正是大多数实时推送场景最需要的品质。掌握 SSE意味着你可以在不引入复杂技术栈的情况下为用户带来流畅的实时体验。