Web实时通信的学习之旅:SSE(Server-Sent Events)的技术详解及简单示例演示

文章目录

      • 一、什么是SSE
      • 二、SSE技术的基本原理
      • 三、SSE适用于场景
      • 四、Node服务端示例
        • 1、协议
        • 2、格式
        • 3、事件
          • 3.1、事件
          • 3.2、事件唯一标识符
          • 3.3、重连事件
        • 4、具体示例
      • 五、客户端示例
        • 1、检测客户端是否支持SSE
        • 2、创建客户端连接
        • 3、事件监听
        • 4、接收事件
        • 5、自定义事件
        • 6、错误处理
        • 7、主动断开连接
        • 8、具体示例
      • 六、注意事项
        • 1、nginx配置
        • 2、EventSource

一、什么是SSE

服务器向浏览器推送信息,除了 WebSocket,还有一种方法:Server-Sent Events(以下简称 SSE)。

SSE(Server-Sent Events)是一种用于实现服务器主动向客户端推送数据的技术,也被称为“事件流”(Event Stream)。它基于 HTTP 协议,利用了其长连接特性,在客户端与服务器之间建立一条持久化连接,并通过这条连接实现服务器向客户端的实时数据推送。

SSE 是HTML5规范的一部分,该规范非常简单,主要由两部分组成:第一部分是服务端与浏览器端的通讯协议(Http协议),第二部分是浏览器端可供JavaScript使用的EventSource对象。

严格意义上来说,Http协议是无法做到服务器主动想浏览器发送协议,但是可以变通下,服务器向客户端发起一个声明,我下面发送的内容将是 text/event-stream 格式的,这个时候浏览器就知道了。响应文本内容是一个持续的数据流,每个数据流由不同的事件组成,并且每个事件可以有一个可选的标识符,不同事件内容之间只能通过回车符\r 和换行符\n来分隔,每个事件可以由多行组成。目前除了IE和Edge,其他浏览器均支持。

二、SSE技术的基本原理

客户端向服务器发送一个GET请求,带有指定的header,表示可以接收事件流类型,并禁用任何的事件缓存。

服务器返回一个响应,带有指定的header,表示事件的媒体类型和编码,以及使用分块传输编码(chunked)来流式传输动态生成的内容。

服务器在有数据更新时,向客户端发送一个或多个名称:值字段组成的事件,由单个换行符分隔。事件之间由两个换行符分隔。服务器可以发送事件数据、事件类型、事件ID和重试时间等字段。

客户端使用EventSource接口来创建一个对象,打开连接,并订阅onopen、onmessage和onerror等事件处理程序来处理连接状态和接收消息。

客户端可以使用GET查询参数来传递数据给服务器,也可以使用close方法来关闭连接。

三、SSE适用于场景

SSE适用场景是指服务器向客户端实时推送数据的场景,例如:

  • 股票价格更新:服务器可以根据股市的变化,实时地将股票价格推送给客户端,让客户端能够及时了解股票的走势和行情。

  • 新闻实时推送:服务器可以根据新闻的更新,实时地将新闻内容或标题推送给客户端,让客户端能够及时了解最新的新闻动态和信息。

  • 在线聊天:服务器可以根据用户的发送,实时地将聊天消息推送给客户端,让客户端能够及时收到和回复消息。

  • 实时监控:服务器可以根据设备的状态,实时地将监控数据或报警信息推送给客户端,让客户端能够及时了解设备的运行情况和异常情况。

SSE适用场景的特点是:

  • 数据更新频繁:服务器需要不断地将最新的数据推送给客户端,保持数据的实时性和准确性。

  • 低延迟:服务器需要尽快地将数据推送给客户端,避免数据的延迟和过期。

  • 单向通信:服务器只需要向客户端推送数据,而不需要接收客户端的数据。

chatGPT 返回的数据 就是使用的SSE 技术

实时数据大屏 如果只是需要展示 实时的数据可以使用SSE技术 而不是非要使用webSocket

四、Node服务端示例

EventSource这个api是一个用于接收服务器发送事件(Server-Sent Events,SSE)的Web API接口。服务器发送事件是一种让服务器端能够主动向客户端发送数据的技术,它使用HTTP协议,并且遵循一定的格式。

1、协议

SSE 协议非常简单,正常的Http请求,更改请起头相关配置即可

Content-Type: text/event-stream,utf-8
Cache-Control: no-cache
Connection: keep-alive
2、格式

文本流基础格式如下,以行为单位的,以冒号分割 Field 和 Value,每行结尾为 \n,每行会Trim掉前后空字符,因此 \r\n 也可以。
每一次发送的信息,由若干个message组成,每个message之间用\n\n分隔。每个message内部由若干行组成,每一行都是如下格式。

field: value\n
field: value\r\n

Field是有5个固定的name

data     // 数据内容
event    // 事件
id       // 数据标识符用id字段表示,相当于每一条数据的编号
retry    // 重试,服务器可以用retry字段,指定浏览器重新发起连接的时间间隔
:        //冒号开头是比较特殊的,表示注释
3、事件

每个事件之间通过空行来分隔。对于每一行来说,冒号(“:”)前面表示的是该行的类型,冒号后面则是对应的值。可能的类型包括:

  • 类型为空白,表示该行是注释,会在处理时被忽略。
  • 类型为 data,表示该行包含的是数据。以 data 开头的行可以出现多次。所有这些行都是该事件的数据。
  • 类型为 event,表示该行用来声明事件的类型。浏览器在收到数据时,会产生对应类型的事件。
  • 类型为 id,表示该行用来声明事件的标识符。
  • 类型为 retry,表示该行用来声明浏览器在连接断开之后进行再次连接之前的等待时间。
3.1、事件

事件之间用\n\n隔断,一般一个事件一行,也可以多行

# 一个事件一行
data: message\n\n
data: message2\n\n


# 一个事件多行
data: {\n
data: "name": "zhangsan",\n
data: "age", 25\n
data: }\n\n

# 自定义事件
event: foo\n   // 自定义事件,名称 foo,触发客户端的foo监听事件
data: a foo event\n\n // 内容

data: an unnamed event\n\n // 默认事件,未指定事件名称,触发客户端 onmessage 事件

event: bar\n   // 自定义时间,名称 bar,触发客户端bar监听事件
data: a bar event\n\n // 内容

3.2、事件唯一标识符

每个事件可以指定一个ID,浏览器会跟踪事件ID,如果发生了重连,浏览器会把最近接收到的时间ID放到 HTTP Header Last-Event-ID 中,作为一种简单的同步机制。

id: eef0128b-48b9-44f7-bbc6-9cc90d32ac4f\n
data: message\n\n
3.3、重连事件

中断连接,客户端一般会3秒重连,但是服务端也可以配置

retry: 10000\n
4、具体示例

在Node.js中使用Server-Sent Events(SSE),你可以创建一个HTTP服务器,并使用res对象的write方法来向客户端发送持久的流信息。

const http = require('http');

const server = http.createServer((req, res) => {
    // 对于SSE请求,需要设置正确的Content-Type和Cache-Control
    // 设置Content-Type头为text/event-stream,这是SSE所需的。
    // 设置Cache-Control头为no-cache,这将防止客户端缓存事件流。
    // 使用Connection: keep-alive,这将保持连接打开,直到服务器明确地关闭连接。
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'Access-Control-Allow-Credentials': true,
        'Access-Control-Allow-Origin': '*'
    });

    // 每隔一定时间发送一次消息
    // 使用res.write()方法将新的数据发送到客户端。
    // 我们在数据前添加了data:前缀,这是SSE事件流所需的。
    // 最后,我们在每个事件之间添加了一个空行\n\n,这是SSE事件流规范要求的,以便客户端可以正确解析事件流
    setInterval(() => {
        const data = `data: ${new Date().toISOString()}\n\n`;
        res.write(data);
    }, 1000);

    // 当客户端断开连接时,清理资源
    req.on('close', () => {
        clearInterval(); // 清除定时器
        res.end(); // 结束响应
    });
});

server.listen(3000, () => {
    console.log('Server is running on port 3000');
});

我们创建了一个简单的HTTP服务器,监听3000端口。对于每个到来的请求,我们设置适当的响应头,并开始向客户端发送事件。我们使用setInterval每秒发送一个包含当前日期和时间的事件。当客户端断开连接时,我们清除定时器并结束响应。这样,你就可以在Node.js中使用SSE向客户端推送实时数据了。

五、客户端示例

1、检测客户端是否支持SSE
function supportsSSE() {
  return !!window.EventSource;
}
2、创建客户端连接

客户端实现就比较简单了,实例化一个EventSource对象,url 可以和服务端同域,也可以跨域,如果跨域的话,需要指定第二个参数withCredentials:true,表示发送Cookie到服务端

//创建一个EventSource对象,用于从sse.php页面接收事件
const evtSource = new EventSource("http://localhost:3000");
3、事件监听

事件源连接后会发送 “open” 事件,可以通过以下两种方式监听

# 方式一:
source.onopen = function(event) {
  // handle open event
};

## 方式二:
source.addEventListener("open", function(event) {
  // handle open event
}, false);

4、接收事件

接收事件同样和上面同样有两种方式。浏览器会自动把一个消息中的多个分段拼接成一个完整的字符串,因此,可以轻松地在这里使用 JSON 序列化和反序列化处理。

# 方式一:
source.onmessage = function(event) {
  var data = event.data;
  var lastEventId = event.lastEventId;
  // handle message
};

## 方式二:
source.addEventListener("message", function(event) { 
  var data = event.data;
  var lastEventId = event.lastEventId;
  // handle message }, false);
5、自定义事件

默认情况下,服务器发送过来的消息,都是默认事件格式的数据,这个时候都会触发onmessage,如果后端自定义事件的话,则不会触发onmessage,这个是否我们需要添加对应的监听事件

source.addEventListener('foo', function (event) {
  var data = event.data;
  // handle message
}, false);
6、错误处理
# 方式一:
source.onerror = function(event) {
  // handle error event
};

## 方式二:
source.addEventListener("error", function(event) {
  // handle error event
}, false);

7、主动断开连接
source.close()
8、具体示例
// 先判断当前浏览器是否支持EventSource事件
if (typeof(EventSource) !== "undefined") {
  // 用JavaScript创建了一个新的EventSource对象,它将从服务器端的/test/server-sent-events路由接收事件流
  const source = new EventSource('/test/server-sent-events', {
    withCredentials: true
  });
  
  每当服务器发送新的事件时,source.onmessage事件处理程序将运行,我们将事件数据解析为JSON对象
  source.onmessage = (event) => {
     const data = JSON.parse(event.data)
     console.log(data)
  }
  
  // close方法用于关闭 SSE 连接。
  source.close();
 
} else {
  console.log('不支持 EventSource')
}

六、注意事项

1、nginx配置
  • 使用nginx做反向代理时需要将proxy_buffering关闭
proxy_buffering off
  • 或者加上响应头部x-accel-buffering,这样nginx就不会给后端响应数据加buffer
x-accel-buffering: no
2、EventSource
  • 连接关闭后会自动重连

  • 需要显示的调用close方法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Day22 代码随想录打卡|字符串篇---实现 strStr()

题目(leecode T28): 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1…

WSL2中使用USB串口实验

一、主要参考网站: Connect USB devices | Microsoft Learn 连接 USB 设备 | Microsoft Learn 二、安装usbipd-win WSL 本身并不支持连接 USB 设备,因此你需要安装开源 usbipd-win 项目 PS C:\Users\issta> winget install --interactive --exact dorssel.usbipd-win …

yaml配置文件的在深度学习中的简单应用

1 .创作灵感 小伙伴们再阅读深度学习模型的代码的时候,经常会遇到yaml格式的配置文件。用这个配置文件是因为我们在训练模型的时候会涉及很多的参数,如果这些参数东一个,西一个,我们调起来的时候就会很不方便,所以用y…

Springboot+vue项目人事管理系统

开发语言:Java 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架:springbootvue JDK版本:jdk1.8 文末获取源码 系统主要分为管理员和普通用户和员工三部分,主要功能包括个人中心,普通用户管理&…

4.用python爬取保存在text中的格式为m3u8的视频

文章目录 一、爬取过程详解1.寻找视频的m3u8链接2.从网页源码中寻找视频的m3u8链接的第二部分内容3.从视频的m3u8链接获取视频 二、完整的代码 一、爬取过程详解 1.寻找视频的m3u8链接 这个文档承接了爬虫专栏的 第一节.python爬虫爬取视频网站的视频可下载的源url&#xff0…

头歌实践教学平台:CG3-v2.0-图形几何变换

第1关:平移、缩放、旋转正方体 一. 任务描述 1. 本关任务 (1) 理解几何变换基本原理, 掌握平移、旋转、缩放变换的方法; (2) 根据平移算法原理补全translation、scale、rotation_x、rotation_y和rotation_z函数; (3) 根据几何变换基本原理,将main函数中的transla…

RK3568 学习笔记 : Linux emmc 内核启动 rootfs 根文件系统无法正常挂载问题的分析

问题描述 平台 : NanoPi-R5C 开发板 RK3568 平台。 手动编译的 Linux 内核,结果发现大概率 emmc 无法正常初始化,导致 rootfs 根文件系统无法正常挂载 Linux 内核版本: 6.1 Linux 内核代码位置: https://github.com…

上网行为监控软件有哪些(上网审计软件)【收藏】

上网行为监控软件(也被称为上网审计软件)正逐渐成为企业信息安全管理的必备工具。 没错! 这些软件通过对员工的上网行为进行全面、细致的监控和审计,帮助企业提升工作效率、保护数据安全,并规范员工的网络使用行为。 …

Springboot+vue项目健身房课程预约平台

开发语言:Java 开发工具:IDEA /Eclipse 数据库:MYSQL5.7 应用服务:Tomcat7/Tomcat8 使用框架:springbootvue JDK版本:jdk1.8 本系统主要实现了首页、个人中心、用户管理、教练管理、会员卡管理、购买会员管理、课程类型管理、课程信息管理、课程购买…

生信新包|LINGER·从单细胞多组学数据推断基因调控网络

题目:Inferring gene regulatory networks from single-cell multiome data using atlas-scale external data 原理 LINGER 是一个计算框架,旨在从单细胞多组学数据推断基因调控网络。 使用基因表达和染色质可及性的计数矩阵以及细胞类型注释作为输入&…

Linux下创建达梦数据库自动备份任务

分享一个自己用的银河麒麟下达梦数据库自动备份任务脚本。 达梦数据库备份脚本。按日期备份,备份后压缩为tar.gz文件,自动清理导出的文件。 备份脚本保留最后30天记录,以节省硬盘空间,可根据具体情况修改。 达梦数据库备份脚本 …

​​​【收录 Hello 算法】第 4 章 数组与链表

第 4 章 数组与链表 数据结构的世界如同一堵厚实的砖墙。 数组的砖块整齐排列,逐个紧贴。链表的砖块分散各处,连接的藤蔓自由地穿梭于砖缝之间。 本章内容 4.1 数组4.2 链表4.3 列表4.4 内存与缓存 *4.5 小结

解决github无法克隆私有仓库,Repository not found问题(2024最新)

一、背景 这个问题出现,是你用了其他主机设备,需要重新clone私有库时,发现一直报找不到仓库,如下报错: remote: Repository not found.二、解决方法 (1)账号密码方式(已不支持&am…

CSDN上是不是有机器人点赞和收藏?

我在CSDN上写作,主要是本来是记录学习工作中的一些知识点,看得人不多本来就能预想到的。 但是今天发现五一写的一篇博客,出现了很奇怪的阅读、点赞、收藏数。只有2个人阅读,但是有8个点赞,还有5个收藏。 我不禁怀疑CS…

怎么扫描二维码看图片?在线制作图片二维码的方法

随着现在二维码的广泛使用,用这个方式来展现内容的情况越来越多,比如扫码看图就是一种很常见的一种类型。将图片生成二维码后通过扫码来调取云端存储的图片查看,这样可以一次预览多张图片并且不会占据内存,能够快速的实现图片内容…

Flutter笔记:Widgets Easier组件库(11)- 使用提示吐丝(Tip Toasts)

Flutter笔记 Widgets Easier组件库(11)使用提示吐丝 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this …

C++之QT文本处理QDir、QFileDialog、QStringList、QFile

一、相应的头文件 #include <QFileDialog> #include <QDir> #include <QStringList> 二、简介 1.QFileDialog 实际效果如下&#xff1a;比如需要选择打开的文件夹或者文件名&#xff0c;通过调用资源管理器的方式进行可视化操作。 代码示例为&#xff1a…

xss漏洞简介

漏洞简介 跨站脚本&#xff08;Cross-site scripting ,简称 XSS&#xff09;是一种经常出现在Web应用程序中的计算机安全漏洞&#xff0c;是由于web应用程序对用户的输入过滤不足而产生的&#xff0c;是代码注入的一种&#xff0c;XSS就是攻击者利用网站漏洞把恶意脚本代码&am…

4.5_shell的执行流控制

##1.for语句## &#xff08;1&#xff09;for语句作用 为循环执行动作 &#xff08;2&#xff09;for语句结构 for 定义变量 do 使用变量&#xff0c;执行动作 done 结束标志 &#xff08;3&#xff09;for语句的基本格式 格式1 格式1&#xff1a;#!/b…

flask框架的初步认识

flask框架的初步认识 这是一个轻量级的网页框架&#xff0c;在运行后&#xff0c;就相当于服务器&#xff0c;当用户输入URL就会触发对应的事件调用方法&#xff0c;返回给用户一个网页文件&#xff0c;并通过自动识别html标签&#xff0c;来为用户呈现对应的样式和效果&#…
最新文章