Server-Sent Events(SSE)是一种允许服务器向客户端推送实时数据的技术。相比传统的轮询或 WebSocket,SSE 提供了更轻量级的解决方案,适用于只需要从服务器到客户端单向通信的场景。
在浏览器端,SSE 通常通过 EventSource
或 EventSourcePolyfill
来实现。然而,在某些现代前端项目中(例如使用 fetch
API 的环境),我们可能会希望以一种更灵活、可控制的方式处理 SSE 流。这时,可以使用一个流行的库:fetch-event-source
。
本文将介绍如何使用 fetch-event-source
库来建立和处理 SSE 连接,并提供完整的代码示例。
什么是 fetch-event-source?
fetch-event-source
是由 GitHub 开发并开源的一个 JavaScript 库,它提供了一个基于 fetch
的接口来消费 Server-Sent Events 流。与原生 EventSource
相比,它具有以下优势:
- 更细粒度的控制(如设置 headers、自定义 fetch 函数)
- 支持 AbortController 控制连接中断
- 更好的错误处理机制
- 支持流式解析事件
- 适用于现代框架(React/Vue/Angular)和 SSR 环境(如 Next.js)
安装
首先确保你的项目中安装了 fetch-event-source
:
npm install @microsoft/fetch-event-source
基本用法
下面是一个基本的使用示例,展示如何使用 fetch-event-source
建立 SSE 连接并监听事件。
示例代码:
import { fetchEventSource } from '@microsoft/fetch-event-source';
const connectSSE = async () => {
try {
await fetchEventSource('https://your-api-endpoint.com/sse', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
},
onopen: async (response) => {
console.log('SSE connection opened:', response);
if (response.ok && response.headers.get('content-type')?.includes('text/event-stream')) {
console.log('Connection is ready to receive events.');
} else {
throw new Error('Unexpected response when opening SSE connection.');
}
},
onmessage: (event) => {
console.log('Received message:', event.data);
// 处理服务器发送的数据
},
onerror: (err) => {
console.error('SSE error occurred:', err);
// 可在此重试连接
},
onclose: () => {
console.log('SSE connection closed');
},
});
} catch (error) {
console.error('Failed to establish SSE connection:', error);
}
};
connectSSE();
回调函数
回调函数 | 描述 |
---|---|
onopen | 当连接成功打开时调用。你可以在这里验证响应头是否正确。 |
onmessage | 每当服务器发送一条消息时触发。event.data 包含实际数据。 |
onerror | 当发生错误时调用(如网络问题、无效响应)。建议进行重连逻辑处理。 |
onclose | 当连接关闭时调用。注意,这不会自动重新连接。 |
自动重连机制
默认情况下,fetch-event-source
不会自动重连。但你可以在 onclose
或 onerror
中手动调用连接函数实现重连:
let retryCount = 0;
const MAX_RETRIES = 5;
const connectWithRetry = async () => {
if (retryCount >= MAX_RETRIES) {
console.warn('Max retries reached. Stopping reconnect attempts.');
return;
}
try {
await fetchEventSource('https://your-api-endpoint.com/sse', {
onopen: ...,
onmessage: ...,
onerror: (err) => {
console.error('Error:', err);
retryCount++;
setTimeout(connectWithRetry, 3000); // 3秒后重试
},
onclose: () => {
retryCount++;
setTimeout(connectWithRetry, 3000);
},
});
} catch (err) {
retryCount++;
setTimeout(connectWithRetry, 3000);
}
};
中断连接
如果你需要主动中断 SSE 连接,可以使用 AbortController
:
const controller = new AbortController();
setTimeout(() => {
controller.abort(); // 手动中断连接
console.log('Connection aborted manually.');
}, 10000);
await fetchEventSource('https://your-api-endpoint.com/sse', {
signal: controller.signal,
onopen: ...
});
实际应用场景
- AI应用的流式回复
- 股票价格实时更新
- 聊天应用中的通知推送
优点总结
- 基于标准 HTTP 协议,兼容性好
- 支持设置请求头、自定义 fetch 方法
- 支持中断重连接(Abort)
- 易于集成到现代前端框架中
- 错误处理更灵活,便于构建健壮的 SSE 客户端
注意事项
- 由于 SSE 是单向通信,如果需要客户端向服务器发送消息的全双工通信,请考虑使用 WebSocket。
- 在生产环境中应合理设置重连策略,避免无限循环重连。
- 如果服务端返回非
text/event-stream
类型的内容,onopen
方法会收到错误。
参考资料
最后
随着时间发展,使用上可能一些变动,对此更详细的内容可以参考“参考资料”中的链接以及官方文档。
如果关于本文您有其他疑问或者建议,欢迎留言,我将尽快回复。