前端 EventSource(SSE)实时通信使用指南(EventSource-polyfill)

文章目录


前言

在现代 Web 应用开发中,实现实时数据更新是提升用户体验的关键需求。EventSource 作为 HTML5 标准中定义的服务器推送技术,为前端开发者提供了一种轻量级、低功耗的实时通信解决方案。本文将从基础概念到实战应用,全面解析 EventSource 的使用方法。


一、什么是 EventSource

EventSource 是 HTML5 规范中定义的 API,它建立了从浏览器到服务器的单向持久连接,允许服务器主动向客户端推送事件数据,非常适合单向实时数据流场景。与传统的轮询(Polling)和 WebSocket 相比,EventSource 具有以下核心特性:

  • 单向通信:仅支持服务器向客户端推送数据,适合新闻更新、通知提醒等场景
  • 自动重连:连接断开时会自动尝试重连,无需手动处理断线逻辑
  • 轻量级协议:基于 HTTP/HTTPS,使用简单的文本格式传输,开销低于 WebSocket
  • 原生支持:浏览器内置实现,无需额外库依赖

二、与其他实时通信技术的对比

技术方案 连接类型 数据传输方式 适用场景 复杂度
轮询 (Polling) 短连接 主动请求 - 响应 简单数据同步
长轮询 (Comet) 伪长连接 阻塞请求等待响应 中等实时性需求
WebSocket 双向长连接 二进制 / 文本 高交互性应用
EventSource 单向长连接 文本事件流 服务器主动推送

三、适用场景

1、 实时通知系统

社交平台新消息提醒、电商订单状态变更、系统公告推送

2、实时数据监控与仪表盘

服务器日志实时监控、系统性能指标(CPU / 内存)展示、股票行情更新

3、新闻与内容实时推送

新闻网站突发新闻推送、直播平台弹幕展示、社交媒体动态更新

4、物联网设备状态监控

智能家居设备状态(温度、湿度)实时显示、工业设备故障告警

5、协作工具实时状态同步

多人在线文档编辑(如飞书文档)的光标位置同步、在线用户状态显示

6、排队系统与预约通知

医院挂号排队进度、餐厅预约叫号、服务窗口等待通知

适用场景特征总结:

  • 单向数据流动:数据仅从服务器流向客户端(如推送通知、更新状态)
  • 实时性要求中等:秒级更新即可满足需求(非毫秒级高频交互)
  • 服务器主动触发:事件由服务器端业务逻辑驱动(如数据变更、用户操作)
  • 多客户端订阅:同一事件需要推送给多个客户端(如广播通知)
  • 轻量级通信:数据格式简单(文本 / JSON),无需二进制传输

三、EventSource 核心用法与 API 详解

快速上手示例:

javascript 复制代码
//创建实例,连接到服务器
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、创建实例

javascript 复制代码
const source = new EventSource(url, configuration);
  • url:服务器端点地址

  • configuration :可选配置对象

    { withCredentials: true } // 跨域时携带凭据


2、事件监听

默认3种类型:

  • onopen:连接建立时触发
  • onerror:连接错误时触发
  • onmessage:接收未指定事件类型的消息

上述事件也可以使用addEventListener方法代替:

javascript 复制代码
// 监听连接打开事件
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: 主动关闭连接
javascript 复制代码
eventSource.close(); // 主动关闭连接

在页面卸载或组件销毁时记得调用

4、自定义事件与数据格式

服务器可以推送自定义类型的事件,前端通过事件类型区分不同的数据处理逻辑,自定义类型事件依然通过addEventListener监听

javascript 复制代码
// 服务器推送的事件流返回数据(文本格式)
// 自定义通知事件
event: notification
data: {"title":"系统通知","body":"您有新的订单"}
javascript 复制代码
// 监听自定义事件类型(由服务器定义)
eventSource.addEventListener('notification', (event) => {
  const notification = JSON.parse(event.data);
  // 这里添加显示通知的函数
}, false);

5、 处理连接断开与异常情况

在实际应用中,需要完善的连接管理策略来处理各种异常情况,可采用指数退避重连策略。

javascript 复制代码
// 最大重连间隔(毫秒)
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 参数法

javascript 复制代码
const authToken = 'eyJhbGxxxxxxxxxxxxxxxx';
const eventSource = new EventSource(`/api/systemLog?token=${encodeURIComponent(authToken)}`);
javascript 复制代码
// 服务器端解析示例 (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 认证法

javascript 复制代码
// 设置认证 Cookie
document.cookie = `auth_token=${authToken}; path=/; SameSite=Lax; Secure`;

// 创建 EventSource
const eventSource = new EventSource('/api/systemLog', {
  withCredentials: true // 携带凭据
});

服务器配置:

javascript 复制代码
Set-Cookie: auth_token=xyz; Path=/; HttpOnly; SameSite=Lax
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Credentials: true

通过设置cookie传递,需要处理跨域配置

方案 3:代理层注入

使用 Nginx 或 API 网关注入请求头:

javascript 复制代码
# nginx.conf
location /sse-proxy/ {
  proxy_pass http://xxxxxxx/api/systemLog;
  
  # 注入自定义头
  proxy_set_header X-Client-ID $http_x_client_id;
  proxy_set_header Authorization "Bearer your-static-token";
  
  proxy_buffering off;
  proxy_read_timeout 24h;
}

客户端:

javascript 复制代码
// 通过代理路径访问
const eventSource = new EventSource('/sse-proxy/');

// 添加客户端 ID(作为普通头)
const clientId = generateUUID();
eventSource._xhr.setRequestHeader('X-Client-ID', clientId);

企业级应用,复杂部署

4、使用第三方库 eventsource-polyfill (推荐)

见下章节介绍


五、eventsource-polyfill(第三方库)

EventSource-polyfill 是一个用于实现 EventSource 接口的 JavaScript 库,主要作用是为原生不支持该接口的浏览器提供兼容性解决方案,以及突破原生 API 的功能限制。推荐使用eventsource-polyfill来替代原生EventSource 。

1、与EventSource比较

(1) 浏览器兼容性

原生EventSource

  • Internet Explorer(全版本)不支持
  • Opera Mini(移动端)不支持
  • 老版本 Safari(<12.1)存在部分支持问题

eventsource-polyfill 支持范围:

  • IE 10+
  • Edge 12+
  • Firefox 3.5+
  • Chrome 4+
  • Safari 5+
  • Opera 11.5+
  • iOS Safari 4.2+
  • Android Browser 3+

(2) 突破原生 API 的功能限制

功能 原生 EventSource Polyfill 版本
自定义请求头 不支持 支持
跨域凭证控制 有限支持 完善支持
请求方法 仅 GET 支持 POST
请求体 不支持 支持
超时控制 可配置

2、eventsource-polyfill使用

1、安装

CDN引入

javascript 复制代码
<script src="https://cdn.jsdelivr.net/npm/eventsource-polyfill/dist/eventsource.min.js"></script>

npm安装

javascript 复制代码
npm install eventsource-polyfill --save

导入模块

javascript 复制代码
import { EventSourcePolyfill } from 'eventsource-polyfill';

2、使用

Eventsource-polyfill完全遵循原生 EventSource 的 API 规范,因此使用方式也是类似

(1)基础示例

javascript 复制代码
// 创建实例(与原生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)自定义请求头

javascript 复制代码
import { EventSourcePolyfill } from 'event-source-polyfill';

const eventSource = new EventSourcePolyfill('https://xxxxxxxx', {
  headers: {
    'Authorization': 'eyJhbxxxxxxxxxxx...',//设置token

  },
  withCredentials: true  // 携带跨域凭据
});

(3) 自定义重连策略

javascript 复制代码
const eventSource = new EventSourcePolyfill('https://xxxxxxxxx', {
 heartbeatTimeout:30000,  //重连时间间隔(ms)
 maxRetries: 10,  // 最大重试次数 
});

(4)post请求

javascript 复制代码
// 发送 POST 请求带请求体
const sse = new EventSourcePolyfill('https://xxxxxxxxx', {
  method: 'POST',
  body: JSON.stringify({ 
    name: '张三',
    age:20
  }),
  headers: {
    'Content-Type': 'application/json'
  }
});

小结:

使用eventsource-polyfill代替EventSource ,前端开发者可以在保持代码简洁的同时,解决原生 EventSource 的功能限制,为用户提供更稳定、更安全的实时通信体验。


总结

EventSource 作为轻量级服务器推送方案,以单向通信、自动重连等特性,在实时通知、数据监控等场景中提供了简洁高效的解决方案。尽管原生 API 存在请求头限制和兼容性问题,但通过代理服务器中转、eventsource-polyfill 等工具,可轻松突破限制并拓展功能。在实际开发中,合理选择 EventSource 与 WebSocket 等技术,结合业务场景优化重连策略与认证机制,便能为用户打造低功耗、高稳定性的实时交互体验 ------ 这正是前端实时通信领域「轻量而不简单」的魅力所在。

相关推荐
anyup7 分钟前
10000+ 个点位轻松展示,使用 Leaflet 实现地图海量标记点聚类
前端·数据可视化·cursor
林太白9 分钟前
Rust认识安装
前端·后端·rust
掘金酱10 分钟前
🔥 稀土掘金 x Trae 夏日寻宝之旅火热进行ing:做任务赢大疆pocket3、Apple watch等丰富大礼
前端·后端·trae
1024小神10 分钟前
tauri项目添加多文件下载功能,并支持下载进度回调显示在前端页面上
前端·javascript
Ace_317508877611 分钟前
义乌购拍立淘API接入指南
前端
不想说话的麋鹿17 分钟前
《NestJS 实战:RBAC 系统管理模块开发 (四)》:用户绑定
前端·后端·全栈
我是谁谁30 分钟前
JavaScript 中的 Map、WeakMap、Set 详解
前端
laperter41 分钟前
vue3项目第三篇
前端
呆呆的心43 分钟前
深入剖析 JavaScript 数据类型与 Symbol 类型的独特魅力😃
前端·javascript·面试
嘉小华1 小时前
Kotlin委托机制详解
前端