为什么要学习 SSE?
随着 AI 技术的爆发式发展,SSE 在以下场景中变得尤为重要:
- AI 聊天机器人流式回复:ChatGPT、Claude 等 AI 助手通过 SSE 逐字输出回复,提供打字机效果
- AI 代码生成:GitHub Copilot 等工具实时生成代码片段
- AI 图像生成进度:Stable Diffusion 等工具显示生成进度和中间结果
- 实时 AI 分析:股票分析、数据挖掘结果的实时推送
SSE vs WebSocket:如何选择?
特性 | SSE | WebSocket |
---|---|---|
通信方向 | 单向(服务端 → 客户端) | 双向 |
协议 | 基于 HTTP | 独立协议 |
复杂度 | 简单 | 相对复杂 |
自动重连 | 内置支持 | 需要手动实现 |
防火墙穿透 | 优秀(HTTP 协议) | 可能被阻止 |
适用场景 | 实时推送、通知、监控 | 实时聊天、游戏、协作 |
浏览器支持 | 广泛支持 | 广泛支持 |
选择建议:
- ✅ 选择 SSE:如果只需要服务端推送数据(如 AI 回复、通知、监控)
- ✅ 选择 WebSocket:如果需要双向实时通信(如在线游戏、协作编辑)
SSE 基础原理
什么是 SSE?
Server-Sent Events (SSE) 是 HTML5 标准的一部分,允许服务器主动向客户端推送数据。它基于 HTTP 协议,使用简单的文本格式传输数据。
基本工作流程
1 | 客户端 服务端 |
最简单的 SSE 示例
让我们从一个最基础的例子开始:
服务端代码(Node.js)
1 | const express = require('express') |
客户端代码(HTML + JavaScript)
1 |
|
这个简单的例子展示了 SSE 的核心概念:服务端持续推送数据,客户端实时接收并显示。
SSE 消息格式详解
SSE 使用简单的文本格式传输数据,每个消息由以下字段组成:
基本字段
1 | field: value |
标准字段说明
1. data
- 数据字段
1 | data: 这是消息内容 |
1 | res.write('data: 这是消息内容\n') |
2. event
- 事件类型
1 | event: user-login |
1 | res.write('event: user-login\n') |
客户端需要监听 user-login
事件:
1 | eventSource.addEventListener('user-login', function (event) { |
3. id
- 事件 ID
1 | id: 123 |
1 | res.write('id: 9527\n') |
4. retry
- 重连间隔
1 | retry: 5000 |
自动重连机制
SSE 的一个重要优势是内置的自动重连功能。当连接断开时,浏览器会自动尝试重新连接。
还是用上面的最简单的 SSE 示例。
- 启动服务后打开页面等待一会
- 停止服务后等待一会
- 重启服务
可以看到前端页面结果如下:
数据续传机制
当网络中断时,客户端可能会错过一些重要消息。为了让客户端重新连接时,能够接受到这些消息,需要实现数据续传。
数据续传原理
数据续传的核心机制是通过 Last-Event-ID 来跟踪消息的连续性:
- 消息标识:服务端为每条消息分配唯一的递增 ID
- ID 存储:客户端将收到的最后一个事件 ID 存储在本地
- 重连检测:客户端重连时,通过
Last-Event-ID
告知服务端最后收到的消息 ID - 补发机制:服务端查找历史消息,将错过的消息批量发送给客户端
- 状态同步:完成补发后,恢复正常的实时消息流
数据续传时序图
1 | sequenceDiagram |
以下是一个例子
1 | // 服务端 |
1 | <!-- 客户端 --> |
总结
Server-Sent Events (SSE) 是基于 HTTP 的服务端推送技术,特别适合 AI 聊天、实时通知等单向数据流场景。本文介绍了 SSE 的基本数据格式,断线重连及数据续传功能。