Server-Sent Events(简称 SSE)是 HTML5 标准中的一个 API,提供了服务器向浏览器主动推送数据的机制。
SSE 与 WebSocket 的比较
SSE 与 WebSocket 类似,都允许浏览器订阅服务器端的数据源。当有新数据生成时,服务器会发送通知给浏览器,以实时更新页面内容。然而,两者在使用场景上有所不同。SSE 更适合单向通信的场景,如股票行情、新闻推送、社交媒体状态更新和 AI 聊天机器人等。而 WebSocket 提供双向通信,适合需要双向交互的应用,如多人游戏和聊天室。
由于 WebSocket 使用双向全双工连接,需要浏览器和服务器都支持 WebSocket 协议。相比之下,SSE 是基于 HTTP 协议的传输方式,无需额外的通信协议支持。此外,SSE 还具有一些 WebSocket 所不具备的特性,如自动重连、事件 ID 和发送任意事件等,这些特性使 SSE 在某些应用场景中更具优势。
准备工作
为了便于验证以下客户端示例代码,建议先克隆 https://github.com/y1j2x34/sse-server-example 项目到本地,并运行 SSE 服务。
浏览器端使用 SSE 的方法
使用 EventSource API
首先,创建一个 EventSource 对象:
const url = "http://localhost:10086/sse";
const source = new EventSource(url, {
withCredentials: false
});
参数说明:
• url
:远程资源的地址。
• withCredentials
:默认为 false
,表示跨域时是否包含 credentials 凭据。
EventSource 对象创建后会立即发起一个 GET 请求,并自动携带 Accept: text/event-stream
请求头。
连接建立后,当接收到数据时,会触发 message
事件,通过 e.data
可以获取服务器发送的数据:
source.addEventListener('message', e => {
console.log(e.data);
});
此外,还有连接建立和关闭的事件:
source.addEventListener('open', e => {
console.log('已建立连接');
});
source.addEventListener('error', e => {
if (source.readyState === EventSource.CLOSED) {
console.log('连接已关闭');
}
});
EventSource 的状态值:
• EventSource.CONNECTING
:连接正在进行。
• EventSource.OPEN
:连接已建立。
• EventSource.CLOSED
:连接已关闭。
需要注意的是,SSE 连接中断或服务器返回数据失败时,都会触发 error
事件,而非 close
事件。根据 SSE 规范,连接中断后会自动重连,重连间隔时间可以在后端响应数据中指定。
使用 fetch API
通过 fetch API 发起 SSE 请求的示例如下:
(async () => {
const response = await fetch('http://127.0.0.1:10086/sse', {
method: 'POST',
headers: {
'Accept': 'text/event-stream'
}
});
const reader = response.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = new TextDecoder().decode(value);
const json = chunk.replace(/^data:\s+/, '').trim();
console.log(json);
}
})();
使用 @microsoft/fetch-event-source
参考:https://github.com/Azure/fetch-event-source
import { fetchEventSource } from '@microsoft/fetch-event-source';
class RetriableError extends Error {}
class FatalError extends Error {}
fetchEventSource('http://127.0.0.1:10086/sse', {
async onopen(response) {
if (response.ok && response.headers.get('content-type') === 'text/event-stream') {
return;
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
throw new FatalError();
} else {
throw new RetriableError();
}
},
onmessage(msg) {
if (msg.event === 'FatalError') {
throw new FatalError(msg.data);
}
},
onclose() {
throw new RetriableError();
},
onerror(err) {
if (err instanceof FatalError) {
throw err;
}
}
});
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步