单向推送也能这么强?SSE比WebSocket的聪明之处
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
什么是 SSE?SSE(Server-Sent Events,服务器推送事件)是一种基于 HTTP 的浏览器事件流技术:浏览器发起一个 GET 请求,服务器保持响应连接,并以 text/event-stream 格式持续向浏览器发送文本事件。
普通 HTTP 通常是“浏览器请求,服务器响应”。SSE 把持续通信的方向改成了“浏览器订阅,服务器主动推送”,但它只负责服务器到浏览器这一条方向。浏览器如果要提交问题、发送指令或确认操作,仍然可以使用普通 POST、PUT 或 DELETE 请求。 SSE 主要解决三个问题:减少高频轮询造成的无效请求、降低服务器发现变化后的通知延迟,以及用浏览器原生 API 简化实时文本流的接收。AI 对话的流式回答、实时股价、比赛比分、部署日志和监控告警,都是典型场景。 一句话总结:SSE 是一条由浏览器订阅、由服务器持续写入的 HTTP 事件流。 为什么轮询和长轮询不够理想?股价每秒变化时,最直观的办法是短轮询:浏览器每隔一秒请求一次“价格变了吗”。如果价格没有变化,请求仍然会经历 DNS、连接复用、鉴权、路由和响应处理,最后只得到一个“没有变化”。
短轮询的取舍很明确:间隔越短,延迟越低,但请求数量越多;间隔越长,资源消耗越低,但用户看到的状态越旧。按每秒一次计算,一个客户端一天会发起 86,400 次查询,即使绝大多数查询都没有新数据。 长轮询把请求挂在服务器上,直到有新数据才响应。它能消除大部分空响应,但一条消息结束后连接就结束,浏览器还得立即发起下一次请求。
长轮询仍然是“一问一答”的 HTTP 交互,主要开销包括: 长轮询适合低频通知、旧浏览器兼容或服务端无法提供流式响应的环境。但对于持续的服务器到浏览器事件流,SSE 更贴合问题本身。 SSE 是如何工作的?SSE 的工作流程只有三步:浏览器声明接受事件流,服务器返回一个不会立即结束的 HTTP 响应,然后持续写入事件。
第一步:浏览器发起 GET 订阅浏览器可以直接使用原生 EventSource: 这会发起一个 GET 请求,并带上类似下面的请求头: 原生 EventSource 只能订阅 URL,不能像 fetch 一样自由设置 Authorization 请求头。实际项目通常使用同源 Cookie 会话认证;跨域时则要明确配置 CORS 和 withCredentials。不要把长期有效的访问令牌直接放进 URL,因为 URL 可能进入日志、历史记录和监控系统。 第二步:服务器返回事件流响应服务器应返回流式响应,并明确告诉中间件不要缓存或缓冲: 服务端不能等到“所有数据都准备好”再一次性返回,而应该在有事件时立即刷新输出。不同语言的写法不同,但本质都是向响应流追加文本并 flush。 以 Node.js 为例: 真实部署中还要检查 Nginx、网关、CDN 和压缩层是否会缓冲响应。SSE 流通常不应被当作普通静态资源缓存;中间件的职责是透传连接、及时刷新数据,并在需要时关闭响应缓冲。 第三步:用空行结束一条事件SSE 是纯文本协议。一条事件由若干字段组成,两个换行符(空行)表示事件结束: 常用字段如下: 服务器可以发送自定义事件,浏览器按事件名监听:
SSE 和 WebSocket 有什么区别?WebSocket 更像一通电话:连接建立后,浏览器和服务器都能随时讲话。SSE 更像收听广播:服务器持续发送,浏览器负责接收;浏览器的操作可以通过普通 HTTP 请求另行提交。
两者不存在绝对的“谁更先进”。WebSocket 提供更完整的双向能力,SSE 则用更少的协议复杂度完成服务器推送。选型的关键不是追求功能最多,而是匹配数据流向。 SSE 的三个实际优势是什么?优势一:标准 HTTP,接入成本低
SSE 不需要额外的升级协议、帧解析器或客户端 SDK。后端只要能返回持久 HTTP 响应,就能逐条写入事件;浏览器则用 EventSource 接收消息。 这会直接降低四类工程成本: 优势二:自动重连与事件续传
浏览器原生 EventSource 在连接异常结束后会自动尝试重连,服务端可以用 retry 建议等待时间。更关键的是,服务器发送 id 后,浏览器重连时会带上 Last-Event-ID,服务端可以据此补发断线期间的事件。 这个能力不是“消息永不丢失”的保证。要实现可靠恢复,服务端仍需要保存一段时间的事件、定义 ID 的顺序,并处理 ID 过期或客户端从未连接的情况。SSE 提供的是协议入口,可靠性需要业务存储和补偿策略完成。 优势三:天然融入 HTTP 生态
SSE 可以复用 HTTPS、Cookie 会话和现有反向代理规则。企业网络通常对 HTTP/HTTPS 的放行和审计更成熟,因此在需要穿越代理、防火墙或统一网关时,SSE 少了一层协议升级的排障工作。 “基于 HTTP”不代表所有中间件无需配置。负载均衡器的空闲超时、响应压缩、代理缓冲、连接数和跨域策略都会影响 SSE。上线前要用真实链路验证事件是否能及时到达浏览器。 HTTP/2 为什么让 SSE 更好用?HTTP/1.1 下,浏览器通常会限制同一域名的并发连接数,常见实现约为 6 条。一个持续的 SSE 连接可能占用其中一条,页面同时加载资源、调用接口或打开多个实时订阅时,连接名额会变得紧张。
HTTP/2 的多路复用把多个请求和响应拆成独立的流,并共享一条 TCP 连接。SSE 只占用其中一个逻辑流,不再单独霸占一个 HTTP/1.1 连接槽位。HTTP/3 也能提供多路复用,但实际是否使用取决于浏览器、服务器和部署链路。 这并不意味着 SSE 没有容量成本。每个订阅仍然会消耗服务端文件描述符、内存、连接状态和消息分发资源;HTTP/2 解决的是浏览器连接复用问题,不是无限扩容方案。 SSE 适合哪些真实场景?如果数据主要从服务器流向浏览器,且浏览器很少需要通过同一通道发消息,SSE 通常是优先候选。
SSE 有哪些限制和常见错误?SSE 的优势来自它的单向和简单,因此也有明确边界: 心跳可以用注释行维持中间链路活跃,例如每 15 到 30 秒发送一次: 心跳不是业务消息,浏览器不会触发 message 事件,但它可以帮助代理发现连接仍在使用。间隔应小于负载均衡器和代理的空闲超时时间。 常见问题SSE 和 WebSocket 的核心区别是什么?SSE 是基于 HTTP 的服务器到浏览器单向事件流,浏览器原生支持自动重连;WebSocket 是持久的全双工通道,双方都能在同一连接上主动发送消息,但重连和状态恢复通常需要应用自行实现。 SSE 会自动重连吗?会。浏览器的 EventSource 在连接异常关闭后会按 retry 或默认策略尝试重连。若事件包含 id,重连请求还会带上 Last-Event-ID,服务端可以从对应位置继续发送。 SSE 能保证消息不丢失吗?不能单独保证。服务端必须持久化或缓存可重放事件、使用单调或可比较的事件 ID,并处理重连、重复投递和过期游标。客户端也应让事件处理具备幂等性。 SSE 能发送 JSON 吗?能。SSE 的协议外壳是文本,通常把 JSON 字符串放进 data 字段,浏览器收到后再调用 JSON.parse。它不是 JSON 专用协议,也不会替你定义字段校验和版本兼容规则。 SSE 适合聊天应用吗?如果聊天主要是服务器推送回复,且用户消息可以通过 POST 提交,SSE 很合适。若需要输入状态、已读回执、在线状态和大量双向事件在同一通道实时交互,WebSocket 更自然。 SSE 和 HTTP/2 是什么关系?SSE 是应用层事件流格式,HTTP/2 是传输 HTTP 请求的协议版本。SSE 可以运行在 HTTP/1.1 或 HTTP/2 上;HTTP/2 的多路复用能缓解同域连接数限制,但不会把 SSE 变成双向协议。 总结:单向不是退而求其次,而是准确匹配需求SSE 用一个普通 HTTP GET 请求建立持久响应,再以 text/event-stream 格式持续推送文本事件。它的价值集中在三个方面:实现简单、原生自动重连与事件续传、能够复用 HTTP 的认证和部署生态。 当数据流向主要是“服务器 → 浏览器”,浏览器很少需要向服务器发消息,或者可以通过传统 API 完成交互时,SSE 往往比 WebSocket 更容易实现、调试和维护。只有当业务真正需要高频双向通信、二进制帧或同一通道内的互动状态时,WebSocket 的复杂度才值得付出。 选择实时通信技术时,先问数据往哪儿流,再问协议能做什么。单向推送做到足够简单,本身就是一种工程上的聪明。 参考资料阅读原文:点击这里 该文章在 2026/8/10 12:35:08 编辑过 |
关键字查询
相关文章
正在查询... |