EventSource
EventSource 建立了从浏览器到服务器的单向持久连接,允许服务器主动向客户端推送事件数据,非常适合单向实时数据流场景。与传统的轮询(Polling)和 WebSocket 相比,EventSource 具有以下核心特性:
单向通信:仅支持服务器向客户端推送数据,适合新闻更新、通知提醒等场景
自动重连:连接断开时会自动尝试重连,无需手动处理断线逻辑
轻量级协议:基于 HTTP/HTTPS,使用简单的文本格式传输,开销低于 WebSocket
原生支持:浏览器内置实现,无需额外库依赖
快速上手示例:
//创建实例,连接到服务器
const eventSource = new EventSource('https://xxxxxxxxxx');
// 监听连接打开事件
eventSource.onopen = function(event) {
console.log('连接已建立:', event);
};
// 监听消息推送
eventSource.onmessage = (event) => {
// event.data 包含服务器发送的文本数据
// 解析JSON数据示例
try {
const data = JSON.parse(event.data);
//可以在此处添加获取数据后的处理逻辑
} catch (error) {
console.error('数据解析失败:', error, event.data);
}
};
// 错误处理(包含自动重连)
eventSource.onerror = (event) => {
if (event.readyState === EventSource.CLOSED) {
console.log('连接已关闭');
}
};关键API详解
1、创建实例
const source = new EventSource(url, configuration);url:服务器端点地址 configuration :可选配置对象
{ withCredentials: true } // 跨域时携带凭据2、事件监听
默认3种类型:
onopen:连接建立时触发
onerror:连接错误时触发
onmessage:接收未指定事件类型的消息
上述事件也可以使用addEventListener方法代替:
// 监听连接打开事件
eventSource.addEventListener('open', (event) => {
console.log('open',event)
});
// 监听错误事件
eventSource.addEventListener('error', (event) => {
console.log('error',event)
});
// 监听消息推送
eventSource.addEventListener('message', (event) => {
console.log('message',event)
});3、连接管理
close: 主动关闭连接
eventSource.close(); // 主动关闭连接在页面卸载或组件销毁时记得调用
4、自定义事件与数据格式 服务器可以推送自定义类型的事件,前端通过事件类型区分不同的数据处理逻辑,自定义类型事件依然通过addEventListener监听
// 服务器推送的事件流返回数据(文本格式)
// 自定义通知事件
event: notification
data: {"title":"系统通知","body":"您有新的订单"}// 监听自定义事件类型(由服务器定义)
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
// 这里添加显示通知的函数
}, false);5、 处理连接断开与异常情况 在实际应用中,需要完善的连接管理策略来处理各种异常情况,可采用指数退避重连策略。
// 最大重连间隔(毫秒)
const maxReconnectInterval = 30000; // 30秒
// 重连间隔增长因子
let reconnectInterval = 1000; // 初始1秒
function connect() {
const source = new EventSource('/events');
source.onerror = event => {
if (event.target.readyState === EventSource.CLOSED) {// 连接已关闭,手动重连
source.close();
setTimeout(connect, reconnectInterval);
reconnectInterval = Math.min(reconnectInterval * 2, maxReconnectInterval );
}
};
source.onopen = () => {
reconnectInterval = 1000; // 重置重连延迟
};
source.onmessage = function(event) {
// 处理消息逻辑...
};
}
connect();指数退避重连策略就是连接失败后定时持续不断重连,每次请求时间间隔 通过指数增长减小请求频率,通过指数退避重连策略可以避免服务器故障雪崩,给服务端恢复时间,减少客户端与服务端无效流量,平衡实时性与设备资源消耗
自定义请求头
请求头设置Token是用户身份鉴权认证常用方式 ,EventSource 原生不支持设置自定义请求头,这是其设计上的一个显著限制。但通过巧妙的技术方案,我们可以绕过这个限制模拟实现自定义请求头功能。
实现可以采用以下方式:
方案 1:URL 参数法
const authToken = 'eyJhbGxxxxxxxxxxxxxxxx';
const eventSource = new EventSource(`/api/systemLog?token=${encodeURIComponent(authToken)}`);// 服务器端解析示例 (Node.js)
app.get('/api/systemLog', (req, res) => {
const token = req.query.token;
if (!validateToken(token)) {
res.status(401).end();
return;
}
res.setHeader('Content-Type', 'text/event-stream');
// ... SSE 实现
});通过URL拼接参数传递token
方案 2:Cookie 认证法
// 设置认证 Cookie
document.cookie = `auth_token=${authToken}; path=/; SameSite=Lax; Secure`;
// 创建 EventSource
const eventSource = new EventSource('/api/systemLog', {
withCredentials: true // 携带凭据
});服务器配置:
Set-Cookie: auth_token=xyz; Path=/; HttpOnly; SameSite=Lax
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Credentials: true通过设置cookie传递,需要处理跨域配置
eventsource-polyfill(第三方库)
EventSource-polyfill 是一个用于实现 EventSource 接口的 JavaScript 库,主要作用是为原生不支持该接口的浏览器提供兼容性解决方案,以及突破原生 API 的功能限制。推荐使用eventsource-polyfill来替代原生EventSource 。
突破原生 API 的功能限制
| 功能 | 原生 EventSource | Polyfill 版本 |
|---|---|---|
| 自定义请求头 | 不支持 | 支持 |
| 跨域凭证控制 | 有限支持 | 完善支持 |
| 请求方法 | 仅 GET | 支持 POST |
| 请求体 | 不支持 | 支持 |
| 超时控制 | 无 | 可配置 |
2、eventsource-polyfill使用 Eventsource-polyfill完全遵循原生 EventSource 的 API 规范,因此使用方式也是类似
(1)基础示例
// 创建实例(与原生API一致)
const eventSource = new EventSourcePolyfill('https://xxxxxxxx');
// 监听事件(同原生EventSource)
eventSource.onopen = () => {
console.log('连接已建立');
};
eventSource.onmessage = (event) => {
console.log('接收数据:', event.data);
// 解析JSON数据
try {
const data = JSON.parse(event.data);
//可以在此处添加获取数据后的处理逻辑
} catch (error) {
console.error('数据解析失败', error);
}
};
eventSource.onerror = (event) => {
console.log('连接错误',event);
};
// 关闭连接
// eventSource.close();(2)自定义请求头
import { EventSourcePolyfill } from 'event-source-polyfill';
const eventSource = new EventSourcePolyfill('https://xxxxxxxx', {
headers: {
'Authorization': 'eyJhbxxxxxxxxxxx...',//设置token
},
withCredentials: true // 携带跨域凭据
});(3) 自定义重连策略
const eventSource = new EventSourcePolyfill('https://xxxxxxxxx', {
heartbeatTimeout:30000, //重连时间间隔(ms)
maxRetries: 10, // 最大重试次数
});(4)post请求
// 发送 POST 请求带请求体
const sse = new EventSourcePolyfill('https://xxxxxxxxx', {
method: 'POST',
body: JSON.stringify({
name: '张三',
age:20
}),
headers: {
'Content-Type': 'application/json'
}
});小结:
使用eventsource-polyfill代替EventSource ,前端开发者可以在保持代码简洁的同时,解决原生 EventSource 的功能限制,为用户提供更稳定、更安全的实时通信体验。