Skip to content

SSE 解析管线

把流式 HTTP 响应转换为 ReadableStream<ServerSentEvent>。此包解析已有 fetch 响应,不是 EventSource,不会自动重连或重新发送 Last-Event-ID。

调用方明确要将响应体按 SSE 解释(即使没有 SSE Content-Type)时使用直接转换器。需要检查响应协议时,优先使用 Response 辅助方法中的 requiredEventStream()。这两条路径都不自行检查状态码;Fetcher 会在结果提取前执行状态校验。

转换阶段

toServerSentEventStream(response: Response): ServerSentEventStream 要求正文非 null,否则抛 EventStreamConvertError(response, 'Response body is null')。管线为 response.body → TextDecoderStream('utf-8') → TextLineTransformStream → ServerSentEventTransformStream。直接转换器不检查状态和 Content-Type;管线会锁定正文,不能同时独立读取。

API输入 → 输出配置
TextLineTransformer字符串 chunk → 去除换行符的字符串无构造参数,保存未完成行状态。
TextLineTransformStream上述转换器的 TransformStream 包装无参数。
ServerSentEventTransformer行 → ServerSentEvent无参数,保留事件状态。
ServerSentEventTransformStream上述转换器的 TransformStream 包装无参数。
ServerSentEventStreamReadableStream<ServerSentEvent> 别名单消费者流,不是事件总线。

行解析支持 LF、CR、CRLF,包含 CR/LF 跨 chunk 的情况。结束时刷新非空未完成行。网络 chunk 不必与行/事件边界重合,UTF-8 解码先处理跨字节分块。

事件字段与边界

ServerSentEvent 必填 event: stringdata: string,可选 id?: stringretry?: numberServerSentEventFields 暴露静态常量 ID = 'id'EVENT = 'event'DATA = 'data'RETRY = 'retry'

空行只在至少出现一个 data 字段时投递事件,多条 data 以 \n 连接。冒号开头的注释和未知字段被忽略。只在首个冒号分隔字段/值,并最多移除值开头一个空格;无冒号行的值为空。每个事件名称默认 'message',输出 id 默认 '';id/retry 跨事件保留直到更新。含 NUL 的 id 被忽略,retry 只接受 ASCII 数字。

正常 EOF 时,即使没有末尾空行,也会投递待完成的 data 事件。只有 id/retry 的帧只更新状态,不投递事件。retry 仅为元数据,解析器不会安排重连。类型化数据和协议结束标记见 JSON 解码

完整示例

ts
import { toServerSentEventStream } from '@ahoo-wang/fetcher-eventstream';

const encoder = new TextEncoder();
const response = new Response(
  new ReadableStream<Uint8Array>({
    start(controller) {
      for (const chunk of [
        'id: 1\r',
        '\ndata: hel',
        'lo\r\n\r\n',
        'data: tail',
      ]) {
        controller.enqueue(encoder.encode(chunk));
      }
      controller.close();
    },
  }),
);
const events = [];
for await (const event of toServerSentEventStream(response)) events.push(event);
console.assert(events.length === 2 && events[0].data === 'hello');
console.assert(events[1].data === 'tail' && events[1].id === '1');

公开符号与源码

符号实现
ServerSentEventStreameventStreamConverter.ts:31
toServerSentEventStreameventStreamConverter.ts:127
ServerSentEventserverSentEventTransformStream.ts:21
ServerSentEventFieldsserverSentEventTransformStream.ts:35
ServerSentEventTransformerserverSentEventTransformStream.ts:88
ServerSentEventTransformStreamserverSentEventTransformStream.ts:178
TextLineTransformertextLineTransformStream.ts:23
TextLineTransformStreamtextLineTransformStream.ts:71

包索引

基于 Apache License 2.0 发布。