首页/新闻资讯/正文详情

undici EventSource 使用与原理详解:在 Node.js 中实现 Server-Sent Events

发布时间:2026/9/27 21:51:58 来源:云帆数科 栏目:资讯中心
undici EventSource 使用与原理详解:在 Node.js 中实现 Server-Sent Events
后端网络通信【免费下载链接】undiciAn HTTP/1.1 client, written from scratch for Node.js项目地址https://gitcode.com/gh_mirrors/un/undici点击查看免费下载EventSource是 undici 提供的 WHATWG 规范 并结合仓库源码从构造参数、实例属性、事件模型、重连机制到流式解析原理带你完整掌握在 undici 中消费 SSE 流的能力。概述WHATWG 标准的 Server-Sent Events 客户端EventSource接口在 undici 中是一个EventTarget的子类见 lib/web/eventsource/eventsource.js它打开一条到服务器的持久 HTTP 连接服务端以text/event-stream内容类型持续推送事件客户端收到后即时派发事件连接不会被关闭。它是浏览器原生EventSource的 Node.js 等价实现遵循 WHATWG Server-Sent Events 处理模型。需要注意两点稳定性该接口标记为Stability: 1 - Experimental实验性从 v6.5.0 开始加入接口可能在后续版本中发生变化。首次构造警告第一次构造EventSource时会发出一次性ExperimentalWarning其code为UNDICI-ES源码见 eventsource.js 构造函数。全局安装该接口还会被安装到globalThis上即globalThis.EventSource可直接使用安装列表见 lib/global.js。最小用法如下import { EventSource } from undici const eventSource new EventSource(http://localhost:3000) eventSource.onmessage (event) { console.log(event.data) }构造函数new EventSource(url[, eventSourceInitDict])参数说明参数类型说明url{string|URL}事件流地址。相对 URL 会基于当前环境的基础 URL 解析。eventSourceInitDict{Object}可选初始化字典包含以下成员eventSourceInitDict支持以下选项withCredentials{boolean}为true时请求的 credentials 模式设为includeCORS attribute 状态设为use-credentials否则 credentials 模式为same-origin。默认false。dispatcher{Dispatcher}底层请求使用的 dispatcher。默认全局 dispatcher。Stability: 0 - Deprecated已弃用请改用node.dispatcher。node{Object}undici 对标准EventSourceInit字典的扩展dispatcher{Dispatcher}底层请求使用的 dispatcher。默认全局 dispatcher。reconnectionTime{number}断线后等待重新建立连接的时间毫秒。服务端可通过retry字段覆盖此值。默认3000。注意dispatcher选项标记为弃用Stability 0推荐使用node.dispatcher。从源码看构造函数会优先取node.dispatcher其次才是顶层dispatcher见 eventsource.jsreconnectionTime的默认值3000与 Chrome 一致Deno 使用 5000定义在 源码常量。构造时的请求行为创建EventSource实例后会立即开始连接url。请求以以下特征发出对应 构造函数源码请求头Accept: text/event-streamcache 模式为no-storeinitiator 类型为other请求由createPotentialCORSRequest构造模式为corscredentials 模式依据withCredentials在same-origin与include之间切换见 lib/web/eventsource/util.js。如果url无法解析会抛出SyntaxError类型的DOMException。仓库测试 test/eventsource/eventsource.js 验证了不传url抛TypeError、非法 URL 抛带Invalid URL消息的 DOMException。带withCredentials的示例import { EventSource } from undici const eventSource new EventSource(http://localhost:3000, { withCredentials: true })自定义 Dispatcher 注入请求头可以通过自定义Dispatcher控制底层请求例如在派发时追加请求头import { EventSource, Agent } from undici class CustomHeaderAgent extends Agent { dispatch (opts) { opts.headers[x-custom-header] hello world return super.dispatch(...arguments) } } const eventSource new EventSource(http://localhost:3000, { node: { dispatcher: new CustomHeaderAgent() } })在 构造函数源码 中this.#dispatcher被直接保存并在每次#connect()时传给底层fetching()因此自定义 dispatcher 会作用于每次连接含重连。实例属性eventSource.readyState{number}只读表示连接状态取值为以下常量之一EventSource.CONNECTING0——连接尚未建立或连接关闭后正在重新建立EventSource.OPEN1——连接已打开正在按收到顺序派发事件EventSource.CLOSED2——连接未打开且不再尝试重连。eventSource.url{string}只读事件流地址为基于环境基础 URL 解析后的最终 URL源码中保存的是new URL(url, baseUrl).href见 eventsource.js。eventSource.withCredentials{boolean}只读表示是否以 CORS credentials 方式实例化true或否false默认值反映构造时传入的withCredentials选项。事件处理器属性属性类型默认值触发时机eventSource.onopen{Function|null}null派发open事件时eventSource.onmessage{Function|null}null派发message事件时eventSource.onerror{Function|null}null派发error事件时赋值函数会注册为对应事件的处理器赋值为null则移除当前处理器。从源码实现看这些 setter 会先removeEventListener旧的处理器再通过webidl.converters.EventHandlerNonNull转换后addEventListener注册新处理器见 eventsource.js。静态常量CONNECTING/OPEN/CLOSEDEventSource.CONNECTING数值常量0EventSource.OPEN数值常量1EventSource.CLOSED数值常量2。它们被定义为只读且不可写的属性同时存在于EventSource构造函数与实例原型上通过Object.defineProperties以writable: false定义见 eventsource.js。方法eventSource.close()关闭连接如有中止底层请求并将readyState置为CLOSED。关闭后EventSource不会再尝试重连对已关闭的实例再次调用close()无任何效果。源码实现eventsource.js为将readyState置为CLOSED然后调用#controller.abort()中止 fetch并清空#request引用。另外#connect()与#reconnect()的入口都会检查readyState CLOSED并直接返回从而保证关闭后不再建立连接。事件Event:open连接建立、readyState变为OPEN时触发监听器收到一个Event对象。import { EventSource } from undici const eventSource new EventSource(http://localhost:3000) eventSource.addEventListener(open, () { console.log(connection opened) })Event:message当收到没有显式event字段的消息时触发v6.15.0 加入。监听器收到一个MessageEvent其data、lastEventId、origin属性由服务端事件填充。命名事件带event字段的事件会在自己的类型名下派发必须通过addEventListener()订阅。下面是一个完整的服务端推送 客户端消费示例import { createServer } from node:http import { EventSource } from undici const server createServer((request, response) { response.writeHead(200, { content-type: text/event-stream, cache-control: no-cache, connection: keep-alive }) response.write(event: ping\n) response.write(data: connected\n\n) const interval setInterval(() { response.write(data: ${Date.now()}\n\n) }, 1000) request.on(close, () clearInterval(interval)) }) server.listen(3000, () { const eventSource new EventSource(http://localhost:3000) // Named event, delivered under its own type. eventSource.addEventListener(ping, (event) { console.log(ping:, event.data) }) // Unnamed event, delivered as message. eventSource.onmessage (event) { console.log(message:, event.data) } })注意示例中服务端发送了event: ping命名事件与若干无event字段的默认事件命名事件只能通过addEventListener(ping, ...)收到默认事件则统一进入onmessage/message。这正是 WHATWG SSE 处理模型中的命名事件按自身类型派发规则。Event:error连接失败或中断时触发监听器收到一个Event对象。当失败可恢复时EventSource回到CONNECTING状态并在重连时间后重试当失败不可恢复时EventSource转为CLOSED且不再重连。v7.11.0 行为变更网络错误后不再重新建立连接而是直接关闭EventSource。import { EventSource } from undici const eventSource new EventSource(http://localhost:3000) eventSource.onerror () { if (eventSource.readyState EventSource.CLOSED) { console.log(connection closed) } else { console.log(reconnecting) } }结合 processResponse 源码 可以看到error事件的几种触发路径响应为中止的网络错误aborted→ 关闭连接并派发error不再重连响应为普通网络错误→ 调用#reconnect()进入重连流程并派发error响应状态码非 200或Content-Type的 essence 不是text/event-stream→ 关闭并派发error连接中途流式传输失败非正常中止→ 关闭并派发error见 pipeline 回调。连接生命周期与重连机制EventSource在每次建立连接时都会克隆原始请求再发起 fetch而不是复用同一请求对象。源码注释eventsource.js解释了原因fetch 会修改传入的请求URL 列表、重定向次数、响应污染、跨源重定向时的头复用会导致重连指向最后一次重定向目标并在累计 20 次重定向后永久失败因此cloneRequest()克隆请求、并单独拷贝urlList。所有重定向301/308 永久重定向与 302/307 临时重定向按相同方式处理。重连流程#reconnect 源码若readyState为CLOSED直接中止将readyState置为CONNECTING派发error事件等待reconnectionTime毫秒后若readyState仍为CONNECTING若本地记录有lastEventId则在请求头中设置Last-Event-ID先删除旧值再设置且会校验值合法性见 isValidHeaderValue 检查重新调用#connect()。两个值得注意的实现细节定时器使用setTimeout(...).unref()因此仅剩重连定时器在跑时不会阻止 Node.js 进程退出重连时间会与maxReconnectionTime 2 ** 31 - 1取最小值。源码注释指出超过该值的延迟包括Infinity会让 Node.js 在 1ms 后触发定时器从而把很长的重连时间变成重连风暴见 eventsource.js。retry字段对重连时间的覆盖服务端可在事件流中发送retry: 毫秒字段客户端解析后会更新当前reconnectionTime。这在 EventSourceStream.processEvent 中实现仅当retry值全部为 ASCII 数字时才生效parseInt解析非法值被忽略。Last-Event-ID断点续传服务端可在事件中发送id: 字符串字段客户端将其记录为lastEventId校验规则是不含U0000NULL 字符见 util.js。重连时该值会通过Last-Event-ID请求头发回服务端实现断点续传例如事件流中途断开后服务端可依据该头从断点继续推送。若某条事件流中携带的id含 NULL 字符该字段会被忽略。流式解析原理EventSourceStream收到合法响应后undici 将响应体通过pipeline接入EventSourceStream一个 object-mode 的Transform流见 eventsource-stream.js逐字节解析text/event-stream格式并把解析结果 push 为MessageEvent。解析器实现了 WHATWG 规范的完整规则parseLine 实现空行结束当前事件若事件有data则派发否则丢弃以:开头的行注释行忽略data:字段累计事件数据同一事件内多行data以\n连接见 源码仅有data字段的事件派发为message类型携带data、lastEventId、originevent:字段为事件命名派发时使用该名称作为事件类型processEventid:字段更新lastEventIdretry:字段更新重连时间BOM 处理流开头若为 UTF-8 BOMEF BB BF会自动剥离handleBOM行结束符兼容LF、CR与CRLF三种行结束方式。每个事件的MessageEvent还带有origin指向响应最终 URL 的 origin跨源重定向后 origin 会更新为最终 origin见 eventsource.js。配置 EventSource 事件大小上限EventSource 相关的限制可以在 dispatcher 上通过eventSource选项配置。具体到Client详见 Client 构造参数eventSource.maxEventSize{number}EventSource 消息允许的最大事件大小字节。设为0可禁用限制。默认buffer.kStringMaxLength。该选项在 DispatcherBase 中被接收并暴露为eventSourceOptions随后在建立连接时传入EventSourceStream见 eventsource.js。当单个事件累计数据超过上限时解析器会抛出EventSource message size exceeded错误错误对象带aborted false见 eventsource-stream.js并导致连接关闭、派发error事件。进阶场景将 EventSource 与 Dispatcher 生命周期配合由于EventSource可注入任意Dispatcher推荐通过node.dispatcher你可以复用已配置的Agent/Client例如配置了代理、TLS、连接池参数的实例来承载事件流请求避免使用全局默认 dispatcher通过自定义Agent.dispatch()拦截请求如追加鉴权头、统计埋点正如上文CustomHeaderAgent示例通过Client的eventSource.maxEventSize收紧或放宽事件大小限制。小结undici 的EventSource提供了一个与浏览器行为一致的 SSE 客户端自动重连含retry字段覆盖与Last-Event-ID断点续传、完整的事件派发模型open/message/error与命名事件、兼容各种行结束符与 BOM 的流式解析器以及可通过 dispatcher 定制请求与事件大小限制的能力。其行为细节均可对照 EventSource 官方文档、实现源码 与 测试用例 进一步验证与探索。赞分享后端网络通信【免费下载链接】undiciAn HTTP/1.1 client, written from scratch for Node.js项目地址https://gitcode.com/gh_mirrors/un/undici点击查看免费下载相关推荐Undici事件流处理EventSource与Server-Sent Events实战Undici事件流处理EventSource与Server Sent Events实战 你是否还在为Node.js应用中的实时数据传输烦恼长轮询效率低下W后端网络通信Oak框架中的Server-Sent Events(SSE)实现详解Oak框架中的Server Sent Events SSE 实现详解 什么是Server Sent Events Server Sent Events 简称SS后端GeoIP2 Java API完整指南轻松实现IP地理位置查询的7个关键步骤GeoIP2 Java API完整指南轻松实现IP地理位置查询的7个关键步骤 GeoIP2 Java API是一个功能强大的开源库专门用于在Java应用中实后端上一篇免费离线跨平台drawio-desktop 流程图桌面工具完整指南下一篇RevokeMsgPatcher 完整实测PC 微信 QQ 防撤回补丁 4 分钟装完撤回彻底失效创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

5.2.6 dma-buf heaps 与 udmabuf:把分配 dma-buf 的权力交给用户态
5.2.6 dma-buf heaps 与 udmabuf:把分配 dma-buf 的权力交给用户态

前面几节里,dma-buf 总是由某个内核驱动导出的:GPU 驱动创建一个 GEM BO,再把它包装成 dma-buf 抛出 fd。可现实里常有这样的需求——用户态想直接拿到一块可跨设备共享、零拷贝的缓冲区,却不想(也不该)为此去调某个具体 GPU/摄像头驱动的私有 ioctl。比如一个相机 HAL 要… · 2026/9/27 21:51:58

网站被黑挂马速查手册:揭秘男女做羞羞完整版网站源码坑
网站被黑挂马速查手册:揭秘男女做羞羞完整版网站源码坑

网站被黑挂马速查手册:揭秘男女做羞羞完整版网站源码坑 网站被黑挂马,后台改密码都没用,浏览器直接弹黄网广告,这就是很多站长深夜崩溃的起点。如果你正盯着满屏的红色警告发呆,手里攥着那份号称“男女做羞羞完整版网站”的源码,别慌,这篇速查手册就是… · 2026/9/27 21:51:58

《基于SpringBoot的儿童孝心活动服务平台的设计与实现》
《基于SpringBoot的儿童孝心活动服务平台的设计与实现》

一、前言当前儿童孝心教育多停留在家庭口头引导,缺乏线上化活动载体和成果记录,家长难以持续追踪,学校和社区也缺少统一的活动组织与评价渠道。 本系统基于 SpringBoot 搭建,采用 MySQL 存储、Vue 前端与 ECharts 可视化&#xff… · 2026/9/27 21:51:40

2026最新外贸建网站报价全拆解,看懂这5点不花冤枉钱
2026最新外贸建网站报价全拆解,看懂这5点不花冤枉钱

2026最新外贸建网站报价全拆解,看懂这5点不花冤枉钱 域名解析报错、服务器连接超时,这些让人头大的技术细节,往往是甲方和乙方扯皮的起点。很多老板在找服务商时,只盯着页面好不好看,却忽略了背后域名备案、服务器配置这些“看不见”的成本,导致后… · 2026/9/27 23:01:01

苏州家具加盟性价比高厂家有哪些,价格公道不玩套路
苏州家具加盟性价比高厂家有哪些,价格公道不玩套路

在家具加盟赛道摸爬滚打多年的从业者都知道,想要找苏州家具加盟性价比高厂家,筛选的核心标准从来都是价格公道不玩套路。很多创业者找遍苏州家具加盟市场,对比了多家品牌家具加盟免费铺货、家具加盟个性化厂家的政策,最后还是会把… · 2026/9/27 23:01:01

网站分辨率自适应代码费用拆解:一文搞懂避坑指南
网站分辨率自适应代码费用拆解:一文搞懂避坑指南

网站分辨率自适应代码费用拆解:一文搞懂避坑指南 找建站公司最怕什么?不是技术不懂,而是报价单上的数字让你心里没底,怕花大钱办小事,更怕被“技术黑箱”糊弄。很多甲方一听到“自适应”三个字,就以为这是高不可攀的技术门槛,结果被收了几万块的“定制… · 2026/9/27 23:00:55

Yolov8训练水污染水质检测数据集 2400张 4类 水污染 带标注 voc yolo 构建一个水污染数据集检测系统
Yolov8训练水污染水质检测数据集 2400张 4类 水污染 带标注 voc yolo 构建一个水污染数据集检测系统

使用Yolov8训练使用 ——水污染水质检测数据集 2400张 4类 水污染 带标注 voc yolo 构建一个水污染数据集检测系统训练使用 ——水污染水质检测数据集 2400张 水污染 带标注 voc yololabel | pic num | box num clean: (587, 589) turbid: (587, 587) pollute: (746, 746) nor… · 2026/9/27 23:00:49

3年踩坑经验:ps网页设计教程视频背后的建站报价陷阱
3年踩坑经验:ps网页设计教程视频背后的建站报价陷阱

3年踩坑经验:ps网页设计教程视频背后的建站报价陷阱 找建站公司最怕什么?不是网站丑,而是 报价单里藏着无数个“坑” 。很多老板拿着 ps网页设计教程视频 里的效果去要求,结果收到的 建站报价… · 2026/9/27 23:00:43

Docker 网络深入:五种通信模式全解析
Docker 网络深入:五种通信模式全解析

1. 引言 容器化技术已经成为现代应用交付的核心,而网络则是容器化架构中最容易让人困惑的部分之一。很多开发者能熟练地编写 Dockerfile、编排 docker-compose,但一旦遇到容器间通信失败、端口映射异常、跨主机互联等问题,往往只能靠重启和试… · 2026/9/27 23:00:37

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码