以服务端事件流回应当前入站请求:先提交响应头,再逐块写入文字,可感知客户端断开与背压。
源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。
# 网页事件流接口规范 0.1.0 本包让应用把当前入站 HTTP 请求回应成服务端事件流(`text/event-stream`):先**立即提交响应头**,程序继续运行,再逐块写入文字;写入受背压,能感知客户端断开,也能正常结束或异常终止。典型用途是持久对象向浏览器或本地软件推送事件、长任务的进度回报、向服务商的长连接下发任务。SSE 帧格式(`id:`、`event:`、`data:`、`retry:`、以冒号起首的注释行、以空行结尾)**由应用自己拼**;本包只把应用给出的文字按 UTF-8 写出,不解析、不校验、不补全帧。`HEAD` 与非 `GET` 请求由应用先判断,本包不替应用决定路由和方法。接口包只依赖标准库。 ## 流柄 `开始入站事件流回应` 返回一个不透明的字符串(流柄),其余四个函数以它作第一个参数。流柄**只在创建它的事件内有效**:另一个事件里的流柄、伪造的字符串、从未创建的流柄一律使调用失败(豫言异常),不会误操作同一事件里的别的流。同一个事件至多开始一次事件流回应,重复开始失败。事件结束后流柄失效;流的结局见“生命周期”。 ## 函数 `开始入站事件流回应` 接受状态码和附加标头列表,**立即提交响应头**,返回流柄,程序继续运行。状态码须在 200 至 299 之间且不是 204、205(这两个状态不能带正文)。内容类型固定为 `text/event-stream; charset=utf-8`,应用不可覆盖;`Cache-Control: no-store` 是默认值,应用可在附加标头里用同名标头覆盖。附加标头是(名,值)列表,至多 32 项,逐项严格校验:名是 1 至 64 字节的 RFC 9110 token(字母、数字与 ``!#$%&'*+-.^_`|~``);值只允许可见 ASCII、空格与制表(0x09、0x20 至 0x7E),至多 8192 字节,因此不含 CR、LF、NUL 与高位字节;名不区分大小写地重复则失败;下列名不允许应用附加:`Content-Length`、`Transfer-Encoding`、`Connection`、`Keep-Alive`、`Upgrade`、`TE`、`Trailer`、`Content-Type`、`Content-Encoding`,以及 `Set-Cookie`、`Set-Cookie2`(凭据类响应用普通答复函数)。违反任何一项都抛豫言异常,此时响应尚未提交,应用仍可用别的答复函数回应。只能在 HTTP 事件里调用(其他事件抛豫言异常);当前事件若已由别的函数(网页答复等)提交过最终响应,再开始事件流是应用的违规,云工宿主会报错并中止本次运行,不一定能被「尝试运行」捕获;反过来,事件流开始之后本事件已有最终响应,再调用网页答复的任何答复函数同样是违规。 `写入入站事件流文字` 把文字按 UTF-8 **立即写出**,每次至多 65536 字节,超限抛豫言异常(先于状态判断);一帧比 64 KiB 长时,应用自行分几次写,字节序保持。返回整数:`0` 已写入;`1` 客户端已断开;`2` 流已由应用结束或中止。空文字不写出,只刷新并返回当前状态。写入**受背压**:缓冲已满时阻塞豫言,直到有空位或客户端断开;缓冲量由宿主与传输决定,规范不承诺具体块数,也不承诺写入调用与网络块一一对应,只承诺字节序。**客户端断开之后应用仍可继续运行**(例如完成计费结算、清理订阅),此后的写入只返回 1,不再阻塞。 `入站事件流已断开` 返回是否已经观察到客户端断开,不阻塞;一旦为阳恒为阳(此后调用了结束或中止也不变)。观察的来源:宿主报告请求已被客户端中止,或响应体读端已取消、出错。已由应用正常结束或中止、且此前未观察到断开的流返回阴。 `结束入站事件流` 正常终止事件流(客户端读到流的正常结束),幂等:已结束、已中止或已断开的流不报错。`中止入站事件流` 异常终止事件流,用于上游失败:宿主使响应体流以错误终止,原因(至多 1024 字节,超限抛异常)只供宿主诊断,**不发给客户端**;幂等。两者之后写入都返回 2。 失败分类:状态、标头、大小、流柄、事件种类等**违规**抛豫言异常;写入时客户端已断开、流已结束属**可恢复的业务情形**,用返回值 1、2 表达,不抛异常。 ## 生命周期与宿主相关的事实 **程序结束前必须调用结束或中止。** 响应头已提交而程序返回时流不会自行结束(除非宿主在事件结束时收尾,见下),客户端会一直等待。**断开的检测依赖宿主与传输**:云工适配用请求的 AbortSignal(须开启兼容标志 `enable_request_signal`,见适配说明)与响应体流错误共同判定;HTTP/1.1 上空闲连接的断开只有在服务端再次写入之后才会被发现,因此需要长时间保持的流应按周期写入心跳(SSE 注释行 `: ping`)。**存活时间**以宿主为准:云工每个事件的豫言实例有墙钟时限(默认 30 秒,应用目录的 `执行配置.json` 可按事件种类改到至多 15 分钟),时限到达后下一次调用宿主失败、事件终止;当前宿主此时不会终止未结束的响应流(客户端看到流停止但连接仍开),这是宿主待改进项,改进前应用应在时限之前自行结束流并让客户端凭 `Last-Event-ID` 重连(如云端项目的 `/events` 20 秒后关闭)。**异常终止在客户端的可见形态依传输而定**:本地 workerd 的 HTTP/1.1 分块响应里客户端读到的是正常结束,宿主日志记一条未捕获异常;需要客户端可靠区分失败的应用应在流里先写一帧明确的错误事件再中止或结束。这些云端行为除注明本地 workerd 已验之外,均“待云端验证”。 ## 跨宿主一致性要求 同一组调用在各宿主上必须得到相同的返回码与异常类别;宿主可以不同的只有缓冲量、块边界与断开被发现的时机。一旦宿主报告断开,其后的写入必须返回 1 且不得阻塞;结束与中止必须幂等;非法标头、超限写入、无效流柄必须在提交响应头之前(对开始)或不改变流状态(对其余)地失败。写入、结束不得因慢读者而使**其他事件**阻塞。 ## 一致性样例 1. 开始(200,空列表)→ 写入 `data: 1` 加空行返回 0 → 结束 → 写入 `x` 返回 2 → 已断开返回阴;客户端依次读到响应头(内容类型固定)、一帧、正常结束。 2. 开始 → 客户端断开 → 写入返回 1,应用继续记录结算 → 已断开返回阳 → 结束 → 写入返回 2、已断开仍为阳。 3. 开始(200,`Content-Type` 或 `Set-Cookie` 或含换行的值)→ 抛豫言异常,响应未提交。 4. 开始 → 写入两帧 → 中止 → 客户端在两帧之后不见正常结束(可见形态依传输)→ 写入返回 2,重复中止与结束都不报错。 5. 写入 65536 字节返回 0,写入 65537 字节抛异常;多字节字符按字节计。 6. 另一个事件拿到的流柄写入抛豫言异常,不影响本事件自己的流。 ## 边界 不解析或生成 SSE 帧,不实现重连与 `Last-Event-ID` 语义(应用用网页入站读取该标头并自行回放),不做心跳、压缩、二进制流、WebSocket 或多路复用;不改变已提交的响应头;不承诺块边界;不在应用外自动结束流;不授予网络能力(授权仍由宿主资源许可管)。响应体只承载 UTF-8 文字。
# 网页事件流公约 0.1.0 此包使客以事件流(`text/event-stream`)答当前入站之请:先**即提响应头**,程序续行,乃逐块书文;书受背压,能察客之断,亦能正终与异终。其用如持久对象向浏览器或本地软件推事、长事回报进度、向服务商长联下任务。SSE 之帧(`id:`、`event:`、`data:`、`retry:`、冒号起首之注行、空行为尾)**客自拼之**;此包惟以 UTF-8 书客所予之文,不析、不校、不补其帧。`HEAD` 与非 `GET` 之请,客先辨之,此包不代客定路与法。接口包惟依标准库。 ## 流柄 `开始入站事件流回应` 返不透明之字符串(流柄),余四术以之为首参。流柄**惟创之之事可用**:他事之柄、伪造之串、未尝创之柄,皆使调用败(豫言之异),不误及同事之他流。一事至多一开事件流之答,再开则败。事毕则柄失;流之终局见“生命周期”。 ## 术 `开始入站事件流回应` 受状态码与附加标头之列,**即提响应头**,返流柄,程序续行。状态须在二百至二百九十九,而非二零四、二零五(二者不可带体)。内容种类恒为 `text/event-stream; charset=utf-8`,客不得覆之;`Cache-Control: no-store` 为默认,客可以同名之头覆之。附加标头为(名,值)之列,至多三十二项,逐项严校:名为一至六十四字节之 RFC 9110 令牌(字母、数字与 ``!#$%&'*+-.^_`|~``);值惟许可见 ASCII、空格与制表(0x09、0x20 至 0x7E),至多八千一百九十二字节,故无 CR、LF、NUL 与高位字节;名不分大小写而重则败;下列名客不得附:`Content-Length`、`Transfer-Encoding`、`Connection`、`Keep-Alive`、`Upgrade`、`TE`、`Trailer`、`Content-Type`、`Content-Encoding`,及 `Set-Cookie`、`Set-Cookie2`(凭据之答用常答之术)。犯其一即抛豫言之异,时响应未提,客仍可以他术答之。惟 HTTP 事可调(他事抛豫言之异);当事若已由他术(网页答复等)提终响应而复开事件流,乃客之违,云工宿主报误而止此运行,未必可以「尝试运行」捕之;反之,事件流既开,此事已有终响应,复调网页答复之诸答术,亦为违。 `写入入站事件流文字` 以 UTF-8 **即书**其文,每次至多六万五千五百三十六字节,逾则抛豫言之异(先于状态之辨);一帧逾六十四 KiB 者,客自分数次书之,字节之序不变。返整数:`0` 已书;`1` 客已断;`2` 流已由客终或止。空文不书,惟刷新而返今状。书**受背压**:缓冲满则阻豫言,直至有隙或客断;缓冲之量由宿主与传输定,公约不承诺块数,亦不承诺书之次数与网络块一一相应,惟承诺字节之序。**客断之后,应用犹可续行**(如毕计费之结算、清订阅),此后之书惟返一,不复阻。 `入站事件流已断开` 返已否察见客断,不阻;一旦为阳,恒为阳(此后终或止亦不易)。所察之源:宿主报请已为客所止,或响应体读端已取消、已败。客已正终或止、而先未察见断者,返阴。 `结束入站事件流` 正终事件流(客读得流之正终),幂等:已终、已止、已断者不报误。`中止入站事件流` 异终事件流,用于上游败:宿主使响应体流以误终;因(至多一千零二十四字节,逾则抛异)惟供宿主诊断,**不告客**;幂等。二者之后,书皆返二。 误之类:状态、标头、大小、流柄、事类等**违规**者抛豫言之异;书时客已断、流已终,乃**可复之业务情形**,以返值一、二表之,不抛异。 ## 生命周期与宿主相关之实 **程序毕前必终或止。** 响应头既提而程序返者,流不自终(除宿主于事毕收尾,见下),客将久候。**断之察,依宿主与传输**:云工适配以请求之 AbortSignal(须开兼容标志 `enable_request_signal`,见适配说明)与响应体流之误共断之;HTTP/1.1 上空闲之联,其断必待服务端再书而后见,故欲久持之流当按期书心跳(SSE 注行 `: ping`)。**存活之久**,以宿主为准:云工每事之豫言实例有墙钟之限(默认三十秒,应用目录之 `执行配置.json` 可依事类改至多十五分钟),限至则下一调宿主即败、事终;今宿主于此不止未终之响应流(客见流止而联仍开),此宿主待改之项,改前客当于限前自终其流,令客凭 `Last-Event-ID` 重联(如云端项目之 `/events` 二十秒而闭)。**异终于客之所见,依传输**:本地 workerd 之 HTTP/1.1 分块答,客所读者为正终,宿主志记一未捕之异;欲使客可靠辨败者,当先书明示误之事件帧,而后止或终。此诸云端之行,除注明本地 workerd 已验者,皆“待云端验证”。 ## 诸宿主一致之要 同一组调用于诸宿主,返码与异类必同;宿主可异者惟缓冲之量、块之界与断之察时。宿主一旦报断,其后之书必返一而不得阻;终与止必幂等;非法标头、逾限之书、无效流柄,对开始须于提响应头之前、对余术须不改流状而败。书与终不得因慢读者而阻**他事**。 ## 一致性样例 一、开始(二百,空列)→ 书 `data: 1` 加空行返零 → 终 → 书 `x` 返二 → 已断开返阴;客依次读响应头(内容种类固定)、一帧、正终。 二、开始 → 客断 → 书返一,客犹记结算 → 已断开返阳 → 终 → 书返二、已断开仍阳。 三、开始(二百,`Content-Type` 或 `Set-Cookie` 或含换行之值)→ 抛豫言之异,响应未提。 四、开始 → 书二帧 → 止 → 客于二帧之后不见正终(所见之形依传输)→ 书返二,再止与再终皆不报误。 五、书六万五千五百三十六字节返零,书六万五千五百三十七字节抛异;多字节字按字节计。 六、他事所得之柄,书之抛豫言之异,无害此事自有之流。 ## 界 不析不造 SSE 帧,不行重联与 `Last-Event-ID` 之义(客以网页入站读其头而自回放),不作心跳、压缩、二进制流、WebSocket 或多路;不易已提之响应头;不保块界;不于客外自终其流;不授网络之能(授权仍归宿主资源许可)。响应体惟载 UTF-8 之文。