从 WebSocket 转向 SSE:轻量实时推送的另一种选择

前言

  • 维护心跳和断线重连,代码越来越复杂;(参考:websocket 的心跳机制你知道几种)
  • 服务端和代理层要支持 WebSocket 协议,配置麻烦;
  • 实际需求只是报表看板、通知推送,根本用不上复杂的双向通信。

于是,我们团队开始思考:

有没有一种更简单的方式,只要"服务端推数据给客户端",不需要那么多额外的心智负担?

答案就是 ------ SSE(Server-Sent Events)


🔍 什么是 SSE?

SSE,全称 Server-Sent Events ,是一种基于 HTTP 长连接 的单向通信机制。

  • 浏览器通过 EventSource 发起一个普通的 HTTP 请求
  • 服务器不断往这个连接推送数据(text/event-stream 格式)
  • 浏览器原生支持接收和处理消息
  • 内置自动重连:如果连接断开(例如网络波动),浏览器会自动尝试重新连接,不需要手动写心跳逻辑

换句话说,SSE 就是一个开箱即用的"服务器 → 客户端推送管道"。


⚔️ SSE vs WebSocket

特性 SSE WebSocket
通信方向 单向(服务端 → 客户端) 全双工(客户端 ↔ 服务端)
协议 HTTP/1.1 长连接 独立的 WebSocket 协议
断线重连 ✅ 内置自动重连 ❌ 需要手动实现心跳与重连
数据格式 文本(UTF-8) 文本 & 二进制
浏览器支持 现代浏览器原生支持 广泛支持
典型场景 报表、看板、日志、通知流 聊天、游戏、协同编辑、高频交互

一句话总结:

  • 只需要"看"的场景 → 用 SSE
  • 既要"看"又要"说"的场景 → 用 WebSocket

📌 使用场景对比

✅ SSE 适合

  • 报表/大屏看板实时数据刷新
  • 股票、天气、日志流
  • 系统通知、消息提醒
  • IoT 数据上报

✅ WebSocket 适合

  • 聊天、IM 系统
  • 协同编辑(Google Docs 类场景)
  • 游戏、实时白板
  • 高频交互、需要双向通信的应用

🛠️ 实战示例

前端:使用 SSE

js 复制代码
// 前端 SSE 示例
const eventSource = new EventSource('/sse');

eventSource.onmessage = (event) => {
  console.log('收到数据:', event.data);
  // 更新到报表看板
};

eventSource.onerror = (err) => {
  console.error('SSE 错误:', err);
};

后端(Node.js Express)

js 复制代码
import express from 'express';
const app = express();

app.get('/sse', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  let count = 0;
  const timer = setInterval(() => {
    count++;
    res.write(`data: ${JSON.stringify({ time: new Date(), value: count })}\n\n`);
  }, 2000);

  req.on('close', () => clearInterval(timer));
});

app.listen(3000, () => console.log('SSE 服务运行在 http://localhost:3000'));

效果

  • 浏览器每隔 2 秒自动收到一条数据
  • 无需轮询,也不用自己写心跳/重连逻辑
  • 断网后,SSE 会自动重连,带着 Last-Event-ID 从断点继续

⚡ 踩坑点与优化

  1. Nginx 代理 SSE

    要关闭 buffering,否则数据会被攒起来再发。

    nginx 复制代码
    location /sse {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Connection '';
        chunked_transfer_encoding off;
        proxy_buffering off;
        proxy_cache off;
        proxy_set_header Cache-Control 'no-cache';
    }
  2. 浏览器兼容性

    • IE 不支持,需要 polyfill
    • Safari 在弱网环境下可能掉线,但会自动重连
  3. 连接数限制

    • Chrome/Firefox 对同一域名的 HTTP 长连接有限制(一般 6 个左右)
    • 多 tab 同时订阅 SSE 时,建议使用 BroadcastChannelSharedWorker 共享连接

🎯 总结

  • WebSocket 功能全面,但需要维护心跳、断线重连,适合高频交互
  • SSE 简单轻量,自带自动重连,适合单向推送

在我们的项目里,原本用 WebSocket 做报表看板,结果发现:

  • 双向通信完全用不上
  • 重连逻辑写了一堆,反而容易出 bug
  • Nginx 配置 WebSocket 还要单独适配

于是,果断切到 SSE,不仅减少了代码量,还让整个链路更稳定。

👉 技术选型的关键是匹配业务需求:

  • 如果只是推数据,SSE 足够优雅。
  • 如果需要互动交流,WebSocket 还是唯一选择。
相关推荐
码农秋3 小时前
Element Plus DatePicker 日期少一天问题:时区解析陷阱与解决方案
前端·vue.js·elementui·dayjs
未来之窗软件服务3 小时前
未来之窗昭和仙君(五十六)页面_预览模式——东方仙盟筑基期
前端·仙盟创梦ide·东方仙盟·昭和仙君·东方仙盟架构
top_designer3 小时前
Illustrato:钢笔工具“退休”了?Text to Vector 零基础矢量生成流
前端·ui·aigc·交互·ux·设计师·平面设计
星哥说事3 小时前
星哥带你玩飞牛NAS-13:自动追番、订阅下载 + 刮削,动漫党彻底解放双手!
前端
donecoding4 小时前
前端AI开发:为什么选择SSE,它与分块传输编码有何不同?axios能处理SSE吗?
前端·人工智能
安_4 小时前
<style scoped>跟<style>有什么区别
前端·vue
姝然_95274 小时前
Claude Code 命令完整文档
前端
wjcroom4 小时前
web版进销存的设计到实现一
前端
无知的前端4 小时前
Flutter常见问题以及解决方案
前端·flutter·dart
BD_Marathon4 小时前
Vue3_Vite构建工程化前端项目
前端