从 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 还是唯一选择。
相关推荐
kyriewen18 小时前
别再 console.log 了:5 个 Chrome DevTools 调试技巧,用过就回不去了
前端·javascript·面试
IT_陈寒19 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
To_OC19 小时前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
Avan_菜菜20 小时前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
DigitalOcean21 小时前
Laravel 开发者已在 DigitalOcean 上开通超过 10 万台服务器
前端·laravel
星始流年21 小时前
从 Tool 到 Skill——基于 LangChain 的服务端Skill实现
前端·langchain·agent
李惟21 小时前
开源本地通信库,纯客户端 RPC,像聊天一样通信
前端
YAwu1121 小时前
深入解析 React 炫彩鼠标跟随标题组件:从坐标定位到动画性能
前端·react.js
GuWenyue21 小时前
排序效率低?5分钟吃透快速排序,性能飙升至O(nlogn)
前端·javascript·面试
OpenTiny社区21 小时前
🎨 看完 GenUI SDK 源码我悟了!
前端·vue.js·github