从 WebSocket 到 SSE:更轻量的实时通信选择

摘要:在实时 Web 应用开发中,WebSocket 一直被认为是“黄金标准”。无论是聊天软件、在线游戏,还是多人协作编辑工具,WebSocket 都能提供稳定高效的双向通信能力。但在很多实际场景中,我们真的需要这么复杂的技术吗?

在实时 Web 应用开发中,WebSocket 一直被认为是“黄金标准”。无论是聊天软件、在线游戏,还是多人协作编辑工具,WebSocket 都能提供稳定高效的双向通信能力。

但在很多实际场景中,我们真的需要这么复杂的技术吗?

想一下这些常见的需求:

  • 一个实时数据大屏,用来展示最新的业务数据

  • 新闻网站需要向用户推送最新的头条消息

  • 后台系统在任务完成后给用户发送一条通知

这些情况有一个共同点:数据只需要从服务器发往客户端,不需要客户端向服务器发送信息。这时候如果还用 WebSocket,就像是为了寄一封信而专门修一条高速公路——虽然强大,但成本太高,也没必要。

这时候,一个更轻量的技术可以很好地解决问题:服务器发送事件(Server-Sent Events,简称 SSE)。它用更简单的方式实现了服务器向客户端的单向数据推送。


什么是 SSE?为什么它更轻量?

SSE 是一种基于 HTTP 的技术,允许服务器通过一个长连接持续向客户端发送数据。它的设计非常简洁,有以下几个优点:

基于 HTTP,无需额外协议

和 WebSocket 需要建立独立的 ws 或 wss 连接不同,SSE 直接使用普通的 HTTP 或 HTTPS 连接。这样做的好处很明显:

  • 不需要特别的服务器支持,任何能处理 HTTP 长连接的后端框架(比如 Node.js、Python、Java 等)都可以使用

  • 更容易通过防火墙和代理,因为它就是普通的 HTTP 流量

  • 协议开销小,消息是纯文本格式,简单易懂

客户端实现非常简单

在前端,你不需要安装任何额外的库。浏览器自带的 EventSource API 就可以直接使用:

// 连接到服务器的事件流
const eventSource = new EventSource('/sse-endpoint');

// 接收服务器发来的消息
eventSource.onmessage = function(event) {
  console.log('收到消息:', event.data);
};

// 处理错误
eventSource.onerror = function(error) {
  console.error('连接出错:', error);
  // 浏览器会自动尝试重新连接
};

代码很简单,不需要自己处理重连逻辑,浏览器会自动管理连接状态。


SSE 和 WebSocket 的对比

特性SSEWebSocket
通信方向单向(服务器到客户端)双向
协议HTTP/HTTPS独立的 WebSocket 协议
连接管理自动重连需要手动实现
数据格式文本文本或二进制
适用场景通知、推送、数据展示聊天、游戏、实时协作

简单来说,如果需要双向通信,比如聊天室,就用 WebSocket。如果只需要接收服务器推送,比如新闻更新或状态通知,SSE 是更轻量、更简单的选择。


一个简单的实时时钟示例

下面用 Node.js 和 Express 框架实现一个简单的 SSE 应用,它会每秒向客户端发送当前时间。

后端代码 (server.js):

const express = require('express');
const app = express();

// 提供静态页面
app.use(express.static('public'));

// SSE 路由
app.get('/sse', (req, res) => {
  // 设置 SSE 需要的响应头
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  
  // 每秒发送一次时间
  const timer = setInterval(() => {
    const timeString = new Date().toLocaleTimeString();
    // SSE 数据格式要求:data: 开头,结尾有两个换行
    res.write(`data: ${timeString}\
\
`);
  }, 1000);
  
  // 客户端断开连接时清理资源
  req.on('close', () => {
    clearInterval(timer);
    res.end();
  });
});

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

前端代码 (public/index.html):

<!DOCTYPE html>
<html>
<head>
    <title>SSE 时钟示例</title>
</head>
<body>
    <h1>当前时间:<span id="time"></span></h1>
    
    <script>
        const timeElement = document.getElementById('time');
        // 创建 SSE 连接
        const eventSource = new EventSource('/sse');
        
        // 接收服务器发送的数据
        eventSource.onmessage = function(event) {
            timeElement.textContent = event.data;
        };
        
        // 处理错误
        eventSource.onerror = function() {
            timeElement.textContent = '连接出错';
        };
    </script>
</body>
</html>

这个例子展示了 SSE 的基本用法:服务器定期发送数据,客户端接收并更新页面。代码很简单,但实现了一个完整的实时功能。


总结:选择合适的技术

技术选型没有绝对的好坏,关键是找到适合具体场景的方案。WebSocket 功能强大,但复杂度也高。对于只需要服务器向客户端推送数据的场景,SSE 是更轻量、更简单的选择。

下次你需要实现实时功能时,可以先问自己:客户端需要向服务器发送数据吗?

如果不需要,那么 SSE 可能是更好的选择。它能减少开发工作量,降低系统复杂度,还能利用 HTTP 的现有基础设施,让你的应用更加高效稳定。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_12904