SSE协议中data:、event:、id:字段需严格按换行分隔规则逐行解析:data:多行拼接用\n连接,event:定义事件类型且最多出现一次,id:提供唯一标识用于断线重连,消息块以\n\n分隔。

SSE 协议中 data:、event: 和 id: 字段的识别与组装,核心在于严格遵循换行分隔规则和字段语法约定,不是靠正则“模糊匹配”,而是按 HTTP 流式响应的文本结构逐行解析。
data: 字段的识别与组装规则
data: 是最常用字段,用于传输实际消息内容。
- 每行以
data:开头,后跟一个空格 + 内容(允许为空) - 若内容含换行符(
\n),需拆成多行data:,每行一个片段 - 多行
data:视为同一消息的连续内容,最终拼接时用\n连接 - 空
data:行(如data:后直接换行)表示空字符串 -
data:行末不能有额外空格或注释
例如:
data:{"status":"running"}
data:{"progress":50}会被客户端合并为:{"status":"running"}\n{"progress":50}
而:
data:first line data:second line
等价于:first line\nsecond line
event: 字段的识别与作用
event: 用于声明该消息的事件类型,影响客户端 EventSource.addEventListener(type, ...) 的触发。
- 必须独占一行,格式为
event: <name>(冒号后需有空格) -
<name>区分大小写,不能含空格或控制字符 - 同一消息块中最多出现一次
event:;若缺失,默认为"message" - 它不参与数据拼接,只设置当前消息的
e.type
例如:
event: update
data:{"value":100}触发的是 update 类型事件,而非默认的 message。
id: 字段的识别与动态组装逻辑
id: 提供消息唯一标识,用于断线重连时恢复位置。
- 格式为
id: <value>,冒号后需空格,<value>可为数字、时间戳或字符串(不含换行) - 每个消息块最多一个
id:;若重复,以最后出现的为准 - 客户端收到后会自动更新内部
lastEventId,下次重连时通过Last-Event-ID请求头带出 -
id:值本身不参与消息内容解析,但必须能被服务端识别为有效游标(如数据库 offset、时间戳、UUID)
例如:
id: 1689325200000
event: stock
data:{"symbol":"AAPL","price":182.3}客户端断开后重连,请求头自动带上 Last-Event-ID: 1689325200000,服务端据此跳过已发消息。
消息块(Event Block)的边界判定
所有字段都归属于同一个“消息块”,其划分规则是:
- 每个消息块由若干行字段组成(
data:、event:、id:、retry:等) - 字段行必须以合法前缀开头(如
data:、event:),否则整行忽略(可作注释,以:开头) - 消息块之间用两个连续换行符(
\n\n) 分隔 - 空行或仅含空白字符的行也会被视作分隔符
示例完整消息块:
id: 1001
event: log
data:User logged in
data:at 2026-05-18T17:14:00Z
id: 1002
event: error
data:{"code":500,"msg":"timeout"}注意:第一块末尾的 \n\n 和第二块开头的空行,共同构成分隔,不可省略。
动态组装建议(服务端侧)
- 不要手动拼接字符串,使用框架原生 SSE 支持(如 Express 的
res.write()配合 chunked 编码) -
data:内容建议 JSON 序列化后直接写入,避免手动转义换行 -
id:推荐用毫秒时间戳或单调递增整数,确保全局有序 - 所有字段行末必须用
\n(LF),不要混用\r\n(CRLF),否则部分客户端解析异常
比如 Node.js 中安全写法:
res.write(`id: ${Date.now()}\n`);
res.write(`event: ${type}\n`);
res.write(`data: ${JSON.stringify(payload)}\n\n`);不复杂但容易忽略。

















