跳到正文
豫言包管理
← 全部包

豫言操作系统网页事件源 0.1.0

豫言 · 库

读取同源的服务器推送事件流:自动重连并携带最后事件号,事件成批进入统一事件队列,宿主按应用处理速度控制读取而不丢事件。

网页事件源接口规范 0.1.0

本包让浏览器里的豫言应用读取同源的服务器推送事件流(Server-Sent Events,text/event-stream)。与浏览器原生 EventSource 相比有两处刻意的不同:一、事件不是逐条回调,而是成批进入统一事件队列(见[网页事件接口规范](../网页事件/规范.汉语.md)),一次回放几千条历史也只产生少量队列事件;二、宿主按应用的处理速度读取网络流,队列里积压过多时暂停读取(由 HTTP 流控把压力传回服务器),因此不会丢失任何消息——原生 EventSource 与统一队列的丢弃策略都做不到这一点。服务端一侧的事件流回应见[网页事件流](../网页事件流/规范.汉语.md)。应用依赖本包后,全部函数都必须实现。

连接行为

宿主按 WHATWG SSE 规范解析响应,并复现 EventSource 的重连语义:

  • 请求头带 Accept: text/event-stream 与 Cache-Control: no-cache,credentials: 'same-origin';已知最后事件号时带 Last-Event-ID(第一次连接用选项的 起始事件号,之后用流里最近收到的 id:)。
  • 只有 HTTP 200 且 Content-Type 为 text/event-stream(忽略参数与大小写)才算连接成功。其他状态码(含 204)与内容类型不对,都是致命错误:投递 错误(已关闭)后不再重连、不再有事件。
  • 流正常结束或网络中断时,投递 错误(重连中),等待重连间隔后自动重连,成功后再投递 打开;重连间隔初始为选项 重连毫秒(默认 3000),服务器发来 retry: 字段时改用它(限制在 100 至 60000 毫秒内)。
  • 事件按 SSE 规范切分:data: 多行以换行连接;event: 给出事件名(默认 message);id: 更新“最后事件号”(含 NUL 的忽略),每个事件带发出时的最后事件号;空 data 不产生事件;注释行(: 开头)忽略;行结束符可为 \n、\r、\r\n;流首的 BOM 忽略;无效 UTF-8 字节按浏览器规则替换为 U+FFFD。
  • 单个事件的数据超过 1 MiB 视为致命错误(已关闭,原因“事件过大”)。

函数

打开事件源 : 字符串(网址) → 字符串(选项 JSON) → 整数

网址 规则同网页请求包(/ 开头的站内路径或同源绝对网址,至多 8192 码元,无控制字符与反斜杠)。选项 是 JSON 对象,可为空文字(视同 {});字段:

| 字段 | 类型与默认 | 规则 | | --- | --- | --- | | 起始事件号 | 文字,默认无 | 至多 256 个 UTF-16 码元、不含换行与 NUL;第一次连接带为 Last-Event-ID,用于从游标续读(例如上次读到的编号) | | 重连毫秒 | 整数,默认 3000 | 100 至 60000;重连间隔的初值 |

未知字段、类型不对、网址非同源、同时已有 8 个事件源时抛事故。返回事件源号(正整数,实例内单调递增,不复用);连接在后台建立。

关闭事件源 : 整数 → 爻

停止事件源并移除它尚未被取走的事件。事件源仍存在(含重连等待中),或有未取走的事件被移除时返回阳;事件源号未知,或它已因致命错误自行关闭且事件已取尽时返回阴。关闭之后保证不再收到该事件源号的事件。

事件

类型 事件流,订阅号 = 事件源号,名称 与 详情 如下(其余字段依网页事件规范):

| 名称 | 详情 | 含义 | | --- | --- | --- | | 打开 | {"重连":爻} | 连接成功;重连 在第一次连接后为阳 | | 消息 | {"批":[{"事件号":"12","事件名":"message","数据":"…"},…]} | 一批事件,1 至 256 项,按到达顺序;一批的数据总量至多约 1 MiB(单个事件更大时它自己成一批) | | 错误 | {"状态":"重连中"或"已关闭","原因":文字,"HTTP状态":整数(可省)} | 连接中断;重连中 后宿主会自动重连(成功则有新的 打开),已关闭 后该事件源终止 |

原因 有:服务端关闭(流正常结束)、网络中断(连接失败、读流出错,含被重定向到别的来源——mode: same-origin 视为网络错误,按重连间隔重试)、HTTP 状态 N(附 HTTP状态)、内容类型不是 text/event-stream、事件过大。同一事件源的事件保持先后:打开 → 若干 消息 → 错误 → 打开 → …。应用处理 消息 批时逐项取 批[i],并自己按 事件号(例如业务里的递增编号)去重——重连可能重放少量已见过的事件。

背压:宿主对每个事件源,只要队列里该事件源未取走的事件多于 8 个,就暂停读取网络流,待应用取走后再继续;暂停期间服务器一侧的写入会按 HTTP 流控受阻(服务端可用[网页事件流](../网页事件流/规范.汉语.md)包的背压感知机制配合)。事件类型 事件流 的队列上限默认 1024,背压保证积压远低于此,不会触发丢弃。应用长时间不取事件时,连接保持暂停,而不是丢消息。

限额与失败分类

| 项 | 限额 | | --- | --- | | 同时存在的事件源 | 8 | | 单个事件数据 | 1 MiB | | 一批事件 | 256 项且约 1 MiB | | 未取走事件(每事件源) | 约 8 批(背压阈值) | | 网址 | 8192 个 UTF-16 码元 |

违规调用(网址不合规或非同源、选项无效、事件源已满、宿主已关闭)抛豫言事故;连接与流的运行时失败通过 错误 事件报告,不抛事故。

一致性样例

  1. 服务器依次发出 id:1 data:a、id:2 event:x data:b:应用先得到 打开,再得到一个 消息 事件,批 为 [{"事件号":"1","事件名":"message","数据":"a"},{"事件号":"2","事件名":"x","数据":"b"}](同一到达窗口内合并为一批也是合法的)。
  2. 服务器发送 data: 两行 第一、第二:一个事件,数据 第一\n第二。
  3. 服务器 3 秒内关闭连接:应用得到 错误(重连中,服务端关闭),随后自动重连,服务器收到 Last-Event-ID: 2,应用得到新的 打开(重连 为阳)。
  4. 服务器返回 404:应用得到 错误(已关闭,HTTP 状态 404),不再重连;返回 text/html:已关闭,原因为内容类型。
  5. 服务器一次回放 5000 条事件而应用暂不取事件:队列里的 事件流 事件不超过约 8 批,连接被暂停;应用取走后继续接收,最终 5000 条无一丢失、无一重复。
  6. 关闭事件源 之后,即使网络里还有数据,也不会再有该号的事件;同时打开第 9 个事件源抛事故。

边界

本包不规定:跨来源事件流(CORS)、自定义请求头与 POST 请求的事件流、fetch 流的通用读取、WebSocket、事件流的服务端写入(见网页事件流包)、断线期间的排队与离线缓存。

依赖

查看包配置

上传历史

当前上传修订:1 ·

  1. 上传修订 1
    下载 ZIP

包层级

父包:豫言操作系统接口

没有子包。