SSE与WebSocket:实时通信选型指南与实现示例

🔹 一、SSE 是什么?

✅ 定义:

SSE(Server-Sent Events) 是一种 基于 HTTP 的、单向的、服务器向客户端推送数据的技术

简单说:服务器"主动发消息"给浏览器,客户端接收即可。


🔹 二、SSE 的核心特性

特性 说明
单向通信 只能由服务器 → 客户端推送数据,客户端无法通过 SSE 向服务器发送消息(除非结合其他方式如 AJAX)
基于 HTTP/1.1 使用普通的 HTTP 协议,支持长连接(持久连接)
自动重连机制 浏览器会自动尝试重新连接,如果连接断开了(比如网络波动)
文本流格式 数据以 text/event-stream MIME 类型传输,格式为纯文本,支持 data:, event:, id:, retry: 等字段
兼容性良好 现代浏览器(Chrome、Firefox、Safari、Edge)均支持,但不支持 IE

🔹 三、SSE 的典型应用场景

场景 说明
实时通知(如系统告警、订单状态更新) 服务器有新事件,立刻推送给前端
股票行情实时刷新 每秒更新一次价格
日志流实时查看 服务器端输出日志,前端实时显示
在线直播评论(轻量级) 比如弹幕,不需要客户端发消息
心跳检测与在线状态 服务器定期发送心跳包,判断客户端是否在线

🔹 四、SSE 与 WebSocket(ws/wss)的对比

对比维度 SSE WebSocket (ws/wss)
通信方向 单向(服务端 → 客户端) 双向(客户端 ↔ 服务端)
协议基础 HTTP/1.1(基于 HTTP) 独立协议(升级为 WebSocket 协议)
是否支持加密 ✅ 可通过 HTTPS 使用(https:// wss:// 完全加密
连接方式 长连接,但基于 HTTP 独立连接,更高效
自动重连 ✅ 浏览器内置支持 ❌ 需手动实现
数据格式 文本流(text/event-stream 二进制或文本(JSON、Protobuf 等)
适用场景 服务器推送数据,客户端接收 实时双向通信(聊天、游戏、协作)
浏览器兼容性 Chrome/Firefox/Safari/Edge(IE 不支持) 所有现代浏览器都支持
开发复杂度 ⭐ 简单,适合快速集成 ⭐⭐⭐ 较复杂,需处理连接管理、心跳、错误处理等

🔹 五、SSE 与 WebSocket 区别

在说区别前,先说说它们之间的共性

共性

  1. 都用于实现实时通信

    • 无论是 SSE 还是 WebSocket,都是为了解决传统 HTTP 请求/响应模式的"延迟"问题。
  2. 都支持长连接(持久连接)

    • 虽然底层机制不同,但都能保持连接打开,实现"服务器主动通知"。
  3. 都常用于现代 Web 应用中

    • 比如:实时聊天、监控面板、通知系统、在线协作工具等。

区别:

关键差异 SSE WebSocket
是否双向 ❌ 否 ✅ 是
是否基于 HTTP ✅ 是 ❌ 否(升级协议)
是否适合复杂交互 ❌ 一般 ✅ 优秀

🔹 六、如何选择?

如果只需要"服务器推消息给客户端",选 SSE(简单、安全、易用);

如果需要"客户端和服务端来回发消息",比如聊天、游戏、协同编辑,选 WebSocket。


🔹 七、应用场景举例

场景:实时股票行情推送

方案 说明
SSE 服务器每秒推送一次行情数据(如价格、涨跌幅),客户端只需监听即可。代码简单,无需维持双向连接。✅ 推荐
WebSocket 客户端连接后,服务器持续推送行情数据。虽然也能实现,但"只推不收"时,WebSocket 显得"杀鸡用牛刀"。⚠️ 不推荐用于单向推送

✅ Flask实现的SSE示例

python 复制代码
import json
import time

from flask import Flask, Response

app = Flask(__name__)


# 模拟实时推送数据
def generate_events():
    """生成 SSE 数据流"""
    counter = 0
    while True:
        # 每隔 2 秒发送一次消息
        time.sleep(2)

        counter += 1
        message = {
            "event": "time_update",
            "id": str(counter),
            "data": f"当前时间: {time.strftime('%Y-%m-%d %H:%M:%S')}",
            "retry": 5000  # 重连间隔 5 秒
        }

        # 以 text/event-stream 格式输出
        yield f"data: {json.dumps(message)}\n\n"


@app.route('/stream')
def stream():
    """SSE 接口:返回事件流"""
    return Response(generate_events(), mimetype='text/event-stream')


@app.route('/')
def index():
    """返回前端 HTML 客户端页面"""
    return '''
<!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <title>SSE 实时消息</title>
        <style>
            body { font-family: Arial, sans-serif; margin: 20px; }
            #log { border: 1px solid #ccc; padding: 10px; height: 400px; overflow-y: scroll; background: #f9f9f9; }
            .msg { margin: 8px 0; padding: 6px; background: #e3f2fd; border-left: 4px solid #2196f3; }
        </style>
    </head>
    <body>
        <h2>🚀 实时消息推送(SSE)</h2>
        <div id="log"></div>

        <script>
            const log = document.getElementById('log');

            // 创建 EventSource 实例,连接到 /stream
            const eventSource = new EventSource('/stream');

            // 监听 message 事件(来自服务器的 data 字段)
            eventSource.onmessage = function(event) {
                const data = JSON.parse(event.data);
                const msgDiv = document.createElement('div');
                msgDiv.className = 'msg';
                msgDiv.textContent = data.data;
                log.appendChild(msgDiv);
                log.scrollTop = log.scrollHeight; // 自动滚动到底部
            };

            // 监听错误事件
            eventSource.onerror = function(event) {
                console.error('SSE 错误:', event);
                alert('与服务器的连接中断,请刷新页面重试。');
            };
        </script>
    </body>
    </html>'''


if __name__ == '__main__':
    print("🚀 启动 Flask SSE 服务...")
    print("访问 http://localhost:5000 查看实时消息")
    app.run(debug=True, host='localhost', port=5000)

Tips

  • Response(..., mimetype='text/event-stream') 必须设置 MIME 类型为 text/event-stream,否则浏览器不识别
  • yield f"data: {json.dumps(...)}\n\n" 每条消息必须以 data: 开头,结尾必须有两个换行符 \n\n
  • eventSource.onmessage 客户端监听来自服务器的消息(对应 data: 字段)
  • retry: 5000 可选字段,表示客户端在断开后等待 5 秒重连
  • 自动重连 浏览器自动实现,无需手动处理

功能扩展建议

  • 推送 JSON 数据 用 json.dumps() 包裹数据
  • 多种事件类型(如 event: alert) 使用 event: xxx 字段区分不同事件
  • 支持多个客户端 Flask 本身支持并发连接,每个客户端独立流
  • 用 Nginx 反向代理 配置 proxy_buffering off; 避免缓冲问题
  • 添加认证/权限控制 在 @app.route('/stream') 前加 @login_required 等装饰器
相关推荐
weixin_425023003 小时前
【Spring Boot 2.7 整合 WebSocket 完整实战】鉴权拦截+在线用户管理+定向消息推送
spring boot·后端·websocket
honor_zhang3 小时前
Vue3使用@vueuse/core集成Websocket实战及携带身份信息的3种方式
websocket·网络协议·身份验证
独断万古他化4 小时前
【Java 实战项目】多用户网页版聊天室:项目总览与用户 & 好友管理模块实现
java·spring boot·后端·websocket·mybatis
英俊潇洒美少年5 小时前
前端六种通信 API
网络·websocket·网络协议
weixin_425023007 小时前
Spring Boot 2.7 + JDK 8 实现 WebSocket 集群分布式部署(基于 Redis Pub/Sub 方案)
java·spring boot·websocket
ETA81 天前
面试官问SSE和WebSocket的区别?看这篇就够了(含心跳机制详解)
websocket·网络协议
赵丙双1 天前
Server-sent events (SSE)
spring·sse·sseemitter
社恐的下水道蟑螂1 天前
WebSocket 从入门到生产落地:原理拆解 + 聊天室全实战,搞定前端实时通信
前端·javascript·websocket
Qinana1 天前
面试官想听什么?WebSocket协议升级、Koa实战与心跳机制全解析
后端·websocket·node.js