SSE 使用一个 HTTP 响应持续向客户端发送文本事件。浏览器通过 EventSource 接收,客户端要提交数据时另发 HTTP 请求。

最小消息格式

响应 Content-Type 为 text/event-stream,内容使用 UTF-8。一个空行结束一个事件:

id: 1
event: update
data: {"text":"hello"}

字段之间不要插空行,否则会变成不同事件。多个 data 行会用换行拼接;注释行以 : 开头,可作为心跳。

字段作用
data本次事件的文本内容
event事件名,缺省时为 message
id浏览器记录的位置,重连时可能作为 Last-Event-ID 发送
retry建议的重连间隔,单位毫秒

接收自定义事件

const source = new EventSource('/events')
source.addEventListener('update', event => {
const data = JSON.parse(event.data)
console.log(data.text)
})
source.onerror = () => console.log('连接中断或请求失败')
// 页面不再需要连接时调用 source.close()

/events 必须是自己的 SSE 接口;这段只展示客户端用法。没有 event 字段时使用 onmessage。原生 EventSource 使用 GET,不能直接设置任意 Authorization 请求头或 POST 请求体。

连接结束不等于任务完成

原生 EventSource 会对可重试的断线自动重连,没有 onclose 事件。有限任务应发送明确的 done 事件,客户端收到后主动 close;网络错误不能当作 done。

设置 id 不会自动保存或补发旧消息,服务端还要实现事件存储和重放。代理缓冲、压缩缓冲、空闲超时也可能让事件迟迟不显示,应观察浏览器 Network 和实际响应。

与 WebSocket 比较时,区别主要在单向/双向和文本/二进制消息;资源消耗与复杂度取决于具体实现,不能一概判断哪个性能更高。

动手实践:Spring Boot SSE 广播、有限流式任务的 done 与错误处理、流式文本的空格与 JSON 编码。

参考:WHATWG SSE 标准。