「JavaScript深入」Server-Sent Events (SSE):轻量级实时通信技术

Server-Sent Events(SSE)

    • SSE 的特点
      • 1. 单向通信
      • 2. 简单易用,浏览器原生支持
      • 3. 持久连接
      • 4. 纯文本传输
      • 5. 自动重连机制
      • 6. 轻量级协议
    • SSE 的实现
      • 服务器端实现(Node.js 示例)
        • 1. HTTP 响应头设置
        • 2. 数据推送模式
        • 3. 服务器端代码示例
      • 数据格式规范详解
        • 1. 完整事件结构
        • 2. 错误处理示例
      • 客户端实现(HTML + JavaScript)
        • HTML + JavaScript 代码示例
        • 高级功能
    • SSE 与 WebSocket 的比较
        • 混合架构实践
    • SSE 的应用场景
    • 安全与性能优化
        • 1. 安全防护
        • 2. 性能调优
    • SSE扩展方案
        • 1. 断线续传实现
        • 2. 二进制数据传输
    • 总结

在现代 Web 应用中,实时数据推送成为了关键需求之一。例如,在股票行情、天气更新、社交通知等应用场景中,客户端需要能够持续接收服务器端的最新数据。Server-Sent Events (SSE) 是一种基于 HTTP 协议的轻量级实时通信技术,能够让服务器主动向客户端推送消息。

下一节分享了「WebSocket:高效的双向实时通信技术」


SSE 的特点

1. 单向通信

SSE 是服务器向客户端推送数据的单向通道。客户端可以持续接收服务器端的更新,但不会主动向服务器发送数据(除非建立额外的请求)。

2. 简单易用,浏览器原生支持

SSE 使用简单的文本格式传输事件,大多数现代浏览器(如 Chrome、Firefox、Edge 和 Safari)都提供了内置支持,无需额外的库或插件。

3. 持久连接

SSE 采用持久 HTTP 连接(HTTP 长连接),服务器可以连续发送数据流,而无需客户端重复发送请求。

4. 纯文本传输

SSE 传输的数据是纯文本格式,消息之间以换行符 (\n\n) 分隔,便于解析和调试。

5. 自动重连机制

如果 SSE 连接因网络故障等原因断开,浏览器会自动尝试重新连接服务器,而无需额外处理。

const es = new EventSource('/sse');
es.onerror = () => { /* 处理中断 */ };
  • 底层原理: SSE协议规范中定义了客户端自动重连机制,当连接异常断开时,浏览器默认以指数退避策略(初始约3秒)尝试重新连接
  • 开发优势: 相比WebSocket需手动实现断线重连,SSE显著降低实时应用开发复杂度
  • 注意事项: 可通过 retry: 字段指定重试间隔(单位:毫秒ms)

6. 轻量级协议

  • 协议开销: 基于纯文本的简单协议格式,每个消息仅增加约20字节头部信息
  • 传输效率: 适用于高频小数据量场景(如实时股票报价),避免WebSocket的握手开销

SSE 的实现

服务器端实现(Node.js 示例)

在服务器端,SSE 通过正确的 HTTP 头部设置来标识事件流,并以特定格式发送数据。

1. HTTP 响应头设置
res.writeHead(200, {'Content-Type': 'text/event-stream', // 必须声明SSE类型'Cache-Control': 'no-cache',         // 禁用浏览器缓存'Connection': 'keep-alive',          // 保持长连接'Access-Control-Allow-Origin': '*'   // CORS配置
});
  • 关键头信息:
    • Content-Type 必须为 text/event-stream
    • Cache-Control: no-cache 防止代理服务器缓存
    • X-Accel-Buffering: no(Nginx环境禁用缓冲)
2. 数据推送模式
setInterval(() => {res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
  • 流式写入: 必须通过分块编码(chunked encoding)持续发送数据
  • 消息边界: 每条消息必须以 \n\n 结尾,字段间用 \n 分隔
  • 性能优化: 使用写缓冲区,避免频繁的TCP包发送
3. 服务器端代码示例
const http = require('http');http.createServer((req, res) => {res.writeHead(200, {'Content-Type': 'text/event-stream','Cache-Control': 'no-cache','Connection': 'keep-alive'});let clientId = 0;const retryInterval = 5000; // 5秒自动重连const eventSender = setInterval(() => {clientId++;const message = `id: ${clientId}\nevent: update\nretry: ${retryInterval}\ndata: This is message number ${clientId}\n\n`;res.write(message);}, 1000);req.on('close', () => {clearInterval(eventSender);});}).listen(3000, () => {console.log('SSE server running at http://localhost:3000/');
});

数据格式规范详解

1. 完整事件结构
event: userUpdate\n
data: {"id": 101, "status": "online"}\n
id: 101-20230301\n
retry: 10000\n\n
  • event:自定义事件类型,触发客户端对应事件监听器
  • data:支持多行数据(每行需以 data: 开头)
    • 建议JSON格式传输结构化数据
  • id:事件ID,用于断线续传(Last-Event-ID请求头)
  • retry:控制重连间隔(单位:毫秒)
2. 错误处理示例
res.write(`event: error\ndata: 服务端异常\n\n`);
  • 客户端通过监听error事件进行异常处理
  • 建议包含错误代码和描述信息的JSON数据

客户端实现(HTML + JavaScript)

在前端,使用 EventSource API 轻松实现 SSE 连接。

HTML + JavaScript 代码示例
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SSE Demo</title><script>document.addEventListener("DOMContentLoaded", function () {const eventSource = new EventSource('http://localhost:3000/api/notifications');// 自定义事件处理eventSource.addEventListener('update', function(event) {console.log('Received update:', event.data);});// 默认消息类型监听eventSource.onmessage = function(event) {console.log('General message:', event.data);};// 错误处理eventSource.onerror = function(err) {console.error('EventSource failed:', err);};});</script>
</head>
<body><h1>Server-Sent Events Demo</h1><p>Check the console for messages.</p>
</body>
</html>
高级功能
// 自定义请求头(需CORS支持)
const es = new EventSource('/api/stream', {withCredentials: true 
});// 连接状态管理
es.onopen = () => console.log('连接已建立');
es.onerror = (e) => {if (e.target.readyState === EventSource.CLOSED) {console.log('连接永久关闭');}
};// 主动关闭连接
document.getElementById('stop').onclick = () => es.close();

SSE 与 WebSocket 的比较

特性SSEWebSocket
协议HTTP长连接独立的ws/wss协议
压缩支持支持gzip/brotli压缩需要扩展实现
消息延迟较高(依赖HTTP层)低延迟(二进制帧)
连接方式服务器推送数据到客户端客户端和服务器可双向通信
适用场景服务器需要频繁更新数据,如新闻推送、日志更新、实时仪表盘(如监控系统)、新闻/社交媒体Feed流、长轮询替代方案等需要实时交互,如聊天应用、多人协作、高频双向通信(如在线游戏)等
浏览器支持原生支持,大多数现代浏览器均支持需要 WebSocket API,部分老旧浏览器不支持
连接管理自动管理重新连接需手动处理连接丢失与重连
混合架构实践
// 组合使用案例:SSE推送通知 + WebSocket实现聊天
const notificationStream = new EventSource('/notifications');
const chatSocket = new WebSocket('wss://chat.example.com');// 消息类型路由处理
function handleMessage(data) {if (data.type === 'notification') {// 使用SSE处理} else if (data.type === 'chat') {// 使用WebSocket处理 }
}

SSE 的应用场景

SSE 适用于以下应用场景:

  • 实时新闻推送:新闻网站可使用 SSE 向用户推送最新的新闻资讯。
  • 股票行情更新:股票交易平台可以用 SSE 传输市场行情数据。
  • 服务器日志实时展示:开发者工具可以通过 SSE 实时显示服务器日志。
  • 社交通知:社交平台可利用 SSE 向用户推送好友动态或点赞通知。

安全与性能优化

1. 安全防护
// 身份验证示例(Cookie + CORS)
app.use('/secure-stream', (req, res, next) => {if (!validateToken(req.cookies.token)) {return res.status(401).end();}next();
});
  • 认证方案: Cookie验证、JWT令牌、OAuth2.0
  • 安全头设置:
    • Content-Security-Policy: default-src 'self'
    • X-Content-Type-Options: nosniff
2. 性能调优
  • 服务端优化:

    • 连接数限制(Nginx worker_connections)
    • 心跳机制保持连接活跃
    setInterval(() => {res.write(':ping\n\n'); // 注释行作为心跳
    }, 30000);
    
  • 客户端优化:

    • 合理设置EventSource并发数
    • 及时关闭不需要的连接

SSE扩展方案

1. 断线续传实现
// 服务端记录最后事件ID
let lastId = 0;
app.get('/resumable-stream', (req, res) => {const clientLastId = req.headers['last-event-id'] || 0;// 从clientLastId之后开始发送数据
});
2. 二进制数据传输
// 通过Base64编码传输
const buffer = await getImageBuffer();
res.write(`data: ${buffer.toString('base64')}\n\n`);// 客户端解码
es.onmessage = (e) => {const img = document.createElement('img');img.src = `data:image/png;base64,${e.data}`;
};

总结

SSE 是一种轻量级的服务器推送技术,适用于服务器单向推送数据的场景。它基于 HTTP,简单易用,支持持久连接和自动重连,广泛应用于实时数据更新场景。尽管相比 WebSocket 功能有限,但对于不需要双向通信的应用,SSE 提供了更简单、更高效的解决方案。

如果你的应用场景涉及实时数据推送,而不需要客户端主动发送消息,那么 SSE 可能是一个理想的选择!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/73883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯2023年第十四届省赛真题-阶乘的和

蓝桥杯2023年第十四届省赛真题-阶乘的和 时间限制: 2s 内存限制: 320MB 提交: 3519 解决: 697 题目描述 给定 n 个数 Ai&#xff0c;问能满足 m! 为∑ni1(Ai!) 的因数的最大的 m 是多少。其中 m! 表示 m 的阶乘&#xff0c;即 1 2 3 m。 输入格式 输入的第一行包含一个整…

影刀RPA拓展-Python变量类型转换

1. Python变量类型转换概述 1.1 类型转换的必要性 Python作为一种动态类型语言&#xff0c;在编程过程中经常需要进行变量类型转换。这主要是因为不同数据类型在存储结构、运算规则和使用场景上存在差异&#xff0c;而在实际开发中&#xff0c;我们常常需要对不同类型的数据进…

Python pyqt+flask做一个简单实用的自动排班系统

这是一个基于Flask和PyQt的排班系统&#xff0c;可以将Web界面嵌入到桌面应用程序中。 系统界面&#xff1a; 功能特点&#xff1a; - 读取员工信息和现有排班表 - 自动生成排班表 - 美观的Web界面 - 独立的桌面应用程序 整体架构&#xff1a; 系统采用前后端分离的架构…

Pycharm接入DeepSeek,提升自动化脚本的写作效率

一.效果展示&#xff1a; 二.实施步骤&#xff1a; 1.DeepSeek官网创建API key&#xff1a; 创建成功后&#xff0c;会生成一个API key&#xff1a; 2. PyCharm工具&#xff0c;打开文件->设置->插件&#xff0c;搜索“Continue”&#xff0c;点击安装 3.安装完成后&…

Java:Arrays类:操作数组的工具类

文章目录 Arrays类常见方法SetAll(); 代码排序如果数组中存储的是自定义对象 Arrays类 常见方法 SetAll(); 注意&#xff1a; 不能用新的数组接是因为修改的是原数组&#xff0c;所以完了要输出原数组发现会产生变化参数是数组下标变成灰色是因为还能简化&#xff08;Lambda…

2025-gazebo配置on vmware,wsl

ros2安装 # 安装ros2, 推荐鱼香ros一键式安装 wget http://fishros.com/install -O fishros && . fishros安装版本&#xff1a;ubuntu24.04 ros2 jazzy gazebo Getting Started with Gazebo? — Gazebo ionic documentation ros与gz的版本对应关系&#xff1a; ​…

格力地产更名“珠免集团“ 全面转型免税赛道

大湾区经济网品牌观察讯&#xff0c;3月18日&#xff0c;格力地产股份有限公司公告宣布&#xff0c;拟将公司名称变更为"珠海珠免集团股份有限公司"&#xff0c;证券简称同步变更为"珠免集团"。此次更名并非简单的品牌焕新&#xff0c;而是标志着这家曾以房…

网络编程--服务器双客户端聊天

写一个服务器和客户端 运行服务器和2个客户端&#xff0c;实现聊天功能 客户端1和客户端2进行聊天&#xff0c;客户端1将聊天数据发送给服务器&#xff0c;服务器将聊天数据转发给客户端2 要求&#xff1a; 服务器使用 select 模型实现 &#xff0c;客户端1使用 poll 模型实现…

k8s主要控制器简述(一)ReplicaSet与Deployment

目录 一、ReplicaSet 关键特性 示例 解释 支持的 Operator 二、Deployment 1. 声明式更新 示例 2. 滚动更新 示例 3. 回滚 示例 4. ReplicaSet 管理 示例 5. 自动恢复 示例 6. 扩展和缩容 示例 示例 一、ReplicaSet ReplicaSet 是 Kubernetes 中的一个核心控…

python中redis操作整理

下载redis命令 pip install redis 连接redis import redis # host是redis主机&#xff0c;需要redis服务端和客户端都起着 redis默认端口是6379 pool redis.ConnectionPool(hostlocalhost, port6379,decode_responsesTrue) r redis.Redis(connection_poolpool)操作字符串 …

自然语言处理入门4——RNN

一般来说&#xff0c;提到自然语言处理&#xff0c;我们都会涉及到循环神经网络&#xff08;RNN&#xff09;&#xff0c;这是因为自然语言可以被看作是一个时间序列&#xff0c;这个时间序列中的元素是一个个的token。传统的前馈神经网络结构简单&#xff0c;但是不能很好的处…

数据结构之链表(双链表)

目录 一、双向带头循环链表 概念 二、哨兵位的头节点 优点&#xff1a; 头节点的初始化 三、带头双向链表的实现 1.双链表的销毁 2.双链表的打印 3.双链表的尾插和头插 尾插&#xff1a; 头插&#xff1a; 4.双链表的尾删和头删 尾删&#xff1a; 头删&#xff1a; …

ASP3605同步降压调节器——满足汽车电子严苛要求的电源芯片方案

ASP3605高效同步降压调节器&#xff0c;通过AEC-Q100 Grade1认证&#xff0c;输入电压4V至15V&#xff0c;输出电流5A&#xff0c;峰值效率94%。车规级型号ASP3605A3U支持-40C至125C工作温度&#xff0c;适用于ADAS、车载信息娱乐系统等场景。 面向汽车电子的核心功能设计 1. …

vue3+Ts+elementPlus二次封装Table分页表格,表格内展示图片、switch开关、支持

目录 一.项目文件结构 二.实现代码 1.子组件&#xff08;表格组件&#xff09; 2.父组件&#xff08;使用表格&#xff09; 一.项目文件结构 1.表格组件&#xff08;子组件&#xff09;位置 2.使用表格组件的页面文件&#xff08;父组件&#xff09;位置 3.演示图片位置 ele…

[特殊字符]1.2.1 新型基础设施建设

&#x1f680; 新型基础设施建设全解析 &#x1f31f; 核心概念与定义 维度详细内容定义以新发展理念为引领&#xff0c;以技术创新为驱动&#xff0c;以信息网络为基础&#xff0c;提供数字转型、智能升级、融合创新服务的基础设施体系。提出背景2018年中央经济工作会议首次提…

SQL Server数据库慢SQL调优

SQL Server中慢SQL会显著降低系统性能并引发级联效应。首先&#xff0c;用户直接体验响应时间延长&#xff0c;核心业务操作&#xff08;如交易处理、报表生成&#xff09;效率下降&#xff0c;导致客户满意度降低甚至业务中断。其次&#xff0c;资源利用率失衡&#xff0c;CPU…

【安全运营】安全运营关于告警降噪的一些梳理

目录 前言一、智能技术层面1、机器学习和 AI 模型训练2、攻击成功判定 二、多源关联分析1、多源设备关联&#xff08;跨设备日志整合&#xff09;2、上下文信息增强 三、业务白名单和策略优化1、动态白名单机制2、阈值和规则调整 四、自动化和流程化1、告警归并与去重2、同类型…

逆向中常见的加密算法识别

1、base64及换表 base64主要是将输入的每3字节&#xff08;共24bit&#xff09;按照每六比特分成一组&#xff0c;变成4个小于64的索引值&#xff0c;然后通过一个索引表得到4个可见的字符。 索引表为一个64字节的字符串&#xff0c;如果在代码中发现引用了这个索引表“ABCDEF…

《UNIX网络编程卷1:套接字联网API》第2章 传输层:TCP、UDP和SCTP

《UNIX网络编程卷1&#xff1a;套接字联网API》第2章 传输层&#xff1a;TCP、UDP和SCTP 2.1 传输层的核心作用与协议选型 传输层是网络协议栈中承上启下的核心层&#xff0c;直接决定应用的通信质量。其主要职责包括&#xff1a; 端到端通信&#xff1a;屏蔽底层网络细节&am…

Eclipse 创建 Java 类

Eclipse 创建 Java 类 引言 Eclipse 是一款功能强大的集成开发环境(IDE),被广泛用于 Java 开发。本文将详细介绍如何在 Eclipse 中创建 Java 类,包括配置开发环境、创建新项目、添加类以及编写类代码等步骤。 配置 Eclipse 开发环境 1. 安装 Eclipse 首先,您需要在您…