从 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 还是唯一选择。
相关推荐
QuantumLeap丶1 分钟前
《uni-app跨平台开发完全指南》- 06 - 页面路由与导航
前端·vue.js·uni-app
CSharp精选营2 分钟前
ASP.NET Core Blazor进阶1:高级组件开发
前端·.net core·blazor
用户904438163246011 分钟前
AI 生成的 ES2024 代码 90% 有坑!3 个底层陷阱 + 避坑工具,项目 / 面试双救命
前端·面试
小p14 分钟前
react学习6:受控组件
前端·react.js
黑云压城After22 分钟前
纯css实现加载动画
服务器·前端·css
鹏多多23 分钟前
Web使用natapp进行内网穿透和预览本地页面
前端·javascript
ttod_qzstudio34 分钟前
Vue 3 Props 定义详解:从基础到进阶
前端·vue.js
钱端工程师35 分钟前
uniapp封装uni.request请求,实现重复接口请求中断上次请求(防抖)
前端·javascript·uni-app
茶憶36 分钟前
uni-app app移动端实现纵向滑块功能,并伴随自动播放
javascript·vue.js·uni-app·html·scss
dcloud_jibinbin37 分钟前
【uniapp】解决小程序分包下的json文件编译后生成到主包的问题
前端·性能优化·微信小程序·uni-app·vue·json