SSE(Server-Sent Events)——W3C标准,允许服务器通过单个HTTP连接以单向模式向客户端发送流数据。与WebSocket不同,SSE基于普通HTTP工作,不需要客户端使用特殊协议或库。根据W3C HTML Living Standard(2025)规范,EventSource API在所有现代浏览器中得到支持,包括Chrome、Firefox、Safari和Edge。
要点
SSE(Server-Sent Events)——一种允许Web服务器在建立连接后随时向客户端发送数据的技术。它由WHATWG作为HTML Living Standard的一部分进行标准化,并使用MIME类型text/event-stream。SSE支持传输文本数据,可以指定消息标识符、事件类型和重新连接延迟。
与需要双向协议和升级请求的WebSocket不同,SSE基于普通HTTP工作。服务器设置Content-Type: text/event-stream头,分块发送数据并保持连接打开。客户端通过浏览器的EventSource API接收数据,该API自动解析流并生成事件。
根据CanIUse(2025)数据,EventSource API在全球97.5%的浏览器中得到支持。在Internet Explorer和一些移动浏览器(Samsung Internet 7.0版本之前)中不受支持。对于这些情况,存在通过XHR流模拟EventSource的polyfill。SSE不适用于HTTP/1.1管道,但完全兼容HTTP/2服务器推送。
SSE于2009年作为HTML5规范的一部分被提出,名为Server-Sent DOM Events。首次实现出现于Opera 9.0,随后是Firefox 6.0(2011)、Chrome 9.0(2011)和Safari 5.0(2010)。2015年,该规范被分离为HTML Living Standard的独立章节。尽管有十年的历史,由于其单向特性,SSE仍然不如WebSocket流行。
SSE的工作机制如下:客户端使用服务器端点的URL创建EventSource实例。浏览器发送带有Accept: text/event-stream头的GET请求。服务器以200 OK状态和Content-Type: text/event-stream头响应,然后开始以event-stream格式发送数据。连接保持打开状态,直到服务器发送终止信号或客户端调用close()。
在服务器端,数据分块传输(分块传输编码)。每个数据块是由字段行(event、data、id、retry)组成的文本消息。服务器可以随时发送消息,这使SSE成为通知和状态更新的理想选择。连接不需要像WebSocket那样持续进行心跳包交换,尽管retry字段控制重新连接频率。
根据性能测试(2024)数据,SSE在消息大小为256字节时,每个连接每秒最多可提供10,000条消息的吞吐量。在服务器端,每个SSE连接消耗约5-10 KB内存,使一台拥有1 GB RAM的服务器能够支持50,000+并发连接。由于没有二进制协议,这比WebSocket显著减少。
text/event-stream格式——一种简单的文本协议,其中每条消息由换行符分隔的命名字段组成。每个字段的格式为“字段名: 值”。消息由两个换行符(\n\n)分隔。
支持的字段:event(事件类型,默认为message)、data(数据字符串,可以多行)、id(最后事件标识符,存储在Last-Event-ID中)、retry(重新连接时间,以毫秒为单位)。注释以冒号(:)开头,解析器会忽略它们,但可用于心跳。
| 字段 | 必需 | 用途 |
|---|---|---|
| event | 否 | 事件类型(默认为message) |
| data | 是 | 消息的数据字符串 |
| id | 否 | 用于Last-Event-ID的事件标识符 |
| retry | 否 | 重新连接延迟(毫秒) |
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001
event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000
event: close
data: Session ended
EventSource API——用于接收SSE的内置浏览器接口。要创建连接,只需使用端点的URL调用构造函数即可。EventSource自动建立连接、处理重新连接并将传入消息解析为JavaScript事件。
EventSource事件:open(连接已建立)、message(收到消息,未指定event)、error(连接错误)。对于自定义事件(event: custom),可以使用addEventListener并指定事件名称。EventSource在重新连接时自动发送Last-Event-ID头,允许服务器从中断点恢复流。
根据MDN文档(2025),EventSource支持CORS和凭据传输(withCredentials)。EventSource不适合传输自定义头或请求体——需要通过fetch + ReadableStream手动实现。EventSource不支持二进制数据——仅支持文本和JSON。
const eventSource = new EventSource('/api/events/stream');
eventSource.addEventListener('open', () => {
console.log('SSE连接已打开');
});
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('已接收:', data);
renderUpdate(data);
});
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
showNotification(notification.text);
});
eventSource.addEventListener('error', (error) => {
console.error('SSE错误:', error);
// 浏览器自动重新连接
});
// 关闭连接
eventSource.close();
SSE和WebSocket——用于实时通信的不同技术,各有优势。WebSocket适用于双向数据交换(聊天、游戏、协作编辑),SSE适用于服务器到客户端的单向流(通知、新闻推送、报价器)。
关键区别——WebSocket需要从HTTP/1.1升级到WebSocket协议(ws://)的请求,这可能会被企业代理阻止。SSE基于普通HTTP工作,可通过所有代理,不需要特殊的服务器配置。SSE实现也更简单——服务器不需要额外的库,只需正确格式化HTTP响应即可。
根据对比测试(2024)数据,在一个服务器进程上,由于协议更简单,SSE比WebSocket支持多30-50%的连接。然而,SSE的延迟更高(50-200毫秒,WebSocket为10-50毫秒),因为SSE使用分块HTTP,而不是带有二进制帧的完全双向流。
| 特性 | SSE | WebSocket |
|---|---|---|
| 方向 | 服务器 → 客户端 | 双向 |
| 协议 | HTTP(text/event-stream) | ws:// / wss:// (RFC 6455) |
| 浏览器 | 97.5%(内置EventSource) | 97%(内置WebSocket) |
| 数据 | 仅文本 / JSON | 文本 + 二进制(Blob、ArrayBuffer) |
| 代理处理 | 通过所有代理 | 需要代理配置 |
| 重新连接 | 自动(浏览器) | 手动实现 |
| 历史记录 | Last-Event-ID | 无内置历史记录 |
在服务器上实现SSE不需要库——只需设置正确的HTTP头并以text/event-stream格式发送数据即可。让我们看看使用内置http模块在Node.js中的实现示例。服务器设置Content-Type和Cache-Control头,然后每隔N秒发送消息。
根据MDN Web Docs(2025),SSE的必需头包括:Content-Type: text/event-stream、Cache-Control: no-cache和Connection: keep-alive。如果没有Cache-Control,浏览器可能会缓存SSE流,导致传输停止。Connection: keep-alive明确指示浏览器保持连接打开。
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let eventId = 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`event: update\n`);
res.write(`data: {"时间": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
}).listen(3000);
from flask import Response, Flask
import time
import json
app = Flask(__name__)
@app.route('/stream')
def stream():
def generate():
event_id = 0
while True:
event_id += 1
data = json.dumps(
{'ticker': 'AAPL', 'price': 150.25})
yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
time.sleep(1)
return Response(generate(),
mimetype='text/event-stream')
在移动应用中使用SSE受到iOS和Android缺乏原生EventSource实现的限制。在移动平台上,SSE通过第三方库实现:在iOS上——通过URLSession和NSURLProtocol,在Android上——通过支持SSE的OkHttp(okhttp-sse)。对于React Native和Flutter,有模拟EventSource的包可用。
在iOS上可以通过URLSessionDataDelegate实现原生SSE。在urlSession(_:dataTask:didReceive:)方法中接收数据时,应用累积缓冲区并手动解析event-stream格式。根据iOS开发博客(2024),由于没有心跳包,iOS上SSE的电池消耗比持续的WebSocket连接低40%。
在Android上,OkHttp提供了EventSource.Factory类用于订阅SSE流。Android应用可以在FCM不可用时使用SSE进行通知,或用于后台数据同步。Android上的SSE与WorkManager配合良好,适用于长期后台任务。根据OkHttp文档(2025),okhttp-sse支持带有自定义监听器的自动重新连接。
常见问题
SSE——通过HTTP的单向传输(服务器→客户端),不需要客户端库。WebSocket——带有二进制协议的双向传输。SSE实现更简单,WebSocket适用于客户端也发送数据的任务。
不,SSE只传输文本数据。对于二进制数据(图像、音频),需要进行Base64编码,这会增加33%的大小。对于二进制流,最好使用WebSocket。
EventSource在中断时自动重新连接。延迟时间由流中的retry字段设置(默认1000毫秒)。重新连接时,浏览器发送Last-Event-ID头,允许服务器从中断点恢复流。
每个浏览器对与同一域名的同时HTTP连接数量都有限制。对于HTTP/1.1——每个域名6-8个连接,对于HTTP/2——最多100个。SSE使用单个连接,因此不会与其他请求竞争。
SSE仅适用于接收消息(传入)。发送消息(传出)需要单独的HTTP请求(POST)。对于完整的聊天,更方便使用WebSocket或Socket.IO,在单个连接中实现双向通信。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。