当前位置: 首页 > news >正文

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方法

相关文章:

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

文章目录 一、什么是SSE二、SSE技术的基本原理三、SSE适用于场景四、Node服务端示例1、协议2、格式3、事件3.1、事件3.2、事件唯一标识符3.3、重连事件 4、具体示例 五、客户端示例1、检测客户端是否支持SSE2、创建客户端连接3、事件监听4、接收事件5、自定义事件6、错误处理7、…...

Apache Flume事务

Apache Flume 中的事务处理是指 Flume Agent 在处理事件流时的一种机制,用于确保数据的可靠传输和处理。 1. 事务概述: Flume 中的事务是指一组事件的传输和处理,这些事件在传输过程中要么全部成功完成,要么全部失败&#xff0…...

根据部门id删除该部门下的员工(事务)

application.properties: 或: application.yml: 新表: 日志对象类: 日志service类: 日志service接口: 日志mapper类: 部门service类: 员工mapper类:...

Java之String类

一、String类常用方法 1.引用类型的比较 我们知道在Java中两个引用遍历是不能用" "号来比较的,而String类重写了父类objects的equals方法, 实现了引用类型的比较 例子 import java.util.Scanner; public class Main { public static void…...

es终止快照恢复进程的方法

方法1、删除索引可以终止,恢复进程。 DELETE index_* // 按通配符删除以index_开头的索引 DELETE _all // 删除全部索引 POST *,-.*/_close 关闭索引 POST *,-.*/_open 打开索引 DELETE *,-.* 删除全部索引方法2、强制重启es 集群也可也终…...

ubantu安装rabbbitmq

ubantu安装rabbbitmq 安装Erlang1、在linux下直接安装2、上传Erlang文件后解压 安装rabbitmq开启web管理接口创建用户及修改guest密码,删除guest默认账号 安装Erlang 1、在linux下直接安装 #运行以下命令直接安装: sudo apt-get install erlang#可运行…...

了解 条码工具 Dynamsoft 在条码读取器中的形态运算

在图像处理中,术语形态学是指分析形状以填充小孔、去除噪声、提取轮廓等的一组操作。形态学操作很像空间卷积中的过滤过程。有两个部分在起作用:结构元素和预定义的计算规则。 点击下载Dynamsoft最新版https://www.evget.com/product/3691/download 结…...

NIO和NIO.2对比

Java NIO (New Input/Output) 是从Java 1.4版本开始引入的一个新的I/O API,用于替代原来的BIO(Blocking I/O)API。NIO提供了更加灵活和高效的网络通信方式,特别适合于高吞吐量的网络编程。NIO的主要特点是非阻塞模式,它…...

Google准备好了吗?OpenAI发布ChatGPT驱动搜索引擎|TodayAI

在科技界波澜壮阔的发展中,OpenAI正式宣布其最新突破——一个全新的基于ChatGPT技术的搜索引擎,旨在直接挑战谷歌在搜索领域的统治地位。这一创新将可能彻底改变用户上网搜索的方式。 据悉,这款AI驱动的搜索引擎利用了ChatGPT的强大功能&…...

乐观锁、悲观锁、互斥锁、读写锁

乐观锁和悲观锁是两种不同的锁机制,用于在多线程环境下解决资源竞争问题。互斥锁和读写锁是两种常见的锁类型,它们都可以用来实现乐观锁或悲观锁。 乐观锁 是一种无锁机制,它假设在多线程环境下对共享资源的操作不会发生冲突,因…...

Gin入门指南:从零开始快速掌握Go Web框架Gin

官网:https://gin-gonic.com/ GitHub:https://github.com/gin-gonic 了解 Gin Gin 是一个使用 Go 语言开发的 Web 框架,它非常轻量级且具有高性能。Gin 提供了快速构建 Web 应用程序所需的基本功能和丰富的中间件支持。 以下是 Gin 框架的一些特点和功能: 快速而高效:…...

Scala里的class、object、case class、case object 、trait

Class(类) 定义和作用 Scala 中的 class 是一种蓝图,用于创建对象(实例)。它定义了对象的状态和行为。类可以包含字段(属性)和方法(函数)。类可以有构造器,…...

移动端自动化测试工具 Appium 之 main 启动

文章目录 一、背景二、生成xml文件2.1、创建xml方法2.2、执行主类MainTest2.3、自动生成的xml2.4、工程目录2.5、执行结果 三、命令行执行appium服务四、主方法启动类五、集成Jenkins六、总结 一、背景 Jenkins 做集成测试是不错的工具,那么UI自动化是否可以&#…...

WT32-ETH01作为TCP Client进行通讯

目录 模块简介WT32-ETH01作为TCP Client设置电脑作为TCP Server设置连接并进行通讯总结 模块简介 WT32-ETH01网关主要功能特点: 采用双核Xtensa⑧32-bit LX6 MCU.集成SPI flash 32Mbit\ SRAM 520KB 支持TCP Server. TCP Client, UDP Server. UDP Client工作模式 支持串口、wif…...

jni 返回二维byte数组

在JNI中返回二维byte数组,你需要在Java中准备一个相应的二维数组来接收这个返回值。在JNI层面,你可以创建一个二维的byte数组,并使用GetByteArrayRegion和SetByteArrayRegion来操作它。 以下是一个简单的例子: public class Jni…...

“webpack-dev-server --config build/webpack.dev.conf.js” 请问这个问题要如何修复

解决方案 修改部署方式: 使用 webpack 来打包你的项目,生成静态文件。在生产环境中,使用 Nginx 或其他 HTTP 服务器来提供服务,而不是使用 webpack-dev-server。 Dockerfile 调整: 确保 Dockerfile 中使用的命令是用于…...

TOOL使用fiddler导出的har文件导入到postman测试接口

在fiddler操作 export → File → Export Sessions → alls-->http arch v1.1 导出的har文件直接拖入到浏览器的调试工具中, 然后复制为curl,导入到postman中即可!...

第十三届蓝桥杯决赛(国赛)真题 Java A 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 火柴棒数字试题 B: 小蓝与钥匙试题 C: 内存空间试题 D: 斐波那契数组试题 E: 交通信号试题 F: 数组个数试题 G: 六六大顺试题 H : \mathrm{H}: H: 选素数试题 I: 图书借阅试题 J \mathrm{J} J : 括号序列树 发现宝藏 前些天发现了一个…...

数据结构_顺序表中基本操作的实现_代码

学习笔记&#xff0c;仅供参考 1.头文件 2.初始化 3.增加值 4.根据下标取值 5.查找 6.插入 7.删除 8.动态增加数组的长度 9.所有代码 10.运行结果 1.头文件 //顺序表的实现——动态分配 #include<stdio.h> #include<stdlib.h> #define InitSize 10 type…...

提升SEO排名!SSL证书对SEO效果的积极影响

搜索引擎优化&#xff08;SEO&#xff09;作为提升网站可见度和吸引有机流量的关键策略&#xff0c;其规则与标准也在不断进化以适应这些变化。其中&#xff0c;安装SSL证书对SEO效果产生的正面影响尤为显著。以下是关于安装SSL证书如何促进SEO效果的详细分析。 一、搜索引擎的…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法

使用 ROS1-Noetic 和 mavros v1.20.1&#xff0c; 携带经纬度海拔的话题主要有三个&#xff1a; /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码&#xff0c;来分析他们的发布过程。发现前两个话题都对应了同一…...

react更新页面数据,操作页面,双向数据绑定

// 路由不是组件的直接跳转use client&#xff0c;useEffect&#xff0c;useRouter&#xff0c;需3个结合&#xff0c; use client表示客户端 use client; import { Button,Card, Space,Tag,Table,message,Input } from antd; import { useEffect,useState } from react; impor…...

HTML版英语学习系统

HTML版英语学习系统 这是一个完全免费、无需安装、功能完整的英语学习工具&#xff0c;使用HTML CSS JavaScript实现。 功能 文本朗读练习 - 输入英文文章&#xff0c;系统朗读帮助练习听力和发音&#xff0c;适合跟读练习&#xff0c;模仿学习&#xff1b;实时词典查询 - 双…...

JavaScript性能优化实战大纲

性能优化的核心目标 降低页面加载时间&#xff0c;减少内存占用&#xff0c;提高代码执行效率&#xff0c;确保流畅的用户体验。 代码层面的优化 减少全局变量使用&#xff0c;避免内存泄漏 // 不好的实践 var globalVar I am global;// 好的实践 (function() {var localV…...