认识
一、认识
SSE
(Server-Sent Events
)是一种基于 HTTP
持久连接的单向数据推送协议,服务端通过设置特定响应头(如 Content-Type: text/event-stream、Cache-Control: no-cache、Connection: keep-alive
),并关闭框架(例如 Koa
)默认的自动响应处理,来确保连接持续开放。服务端按 SSE
规范生成消息(每条消息以 data:
开头,以两个换行符结束),并在客户端断开时清理定时器等资源以避免内存泄露。客户端接收方式则主要有三种: 利用 Fetch
结合 ReadableStream
进行 POST
请求与流数据读取,采用 EventSource
处理 GET
请求并自动解析事件数据,或通过 XMLHttpRequest
的 onprogress
事件手动管理数据缓冲。
SSE
(Server-Sent Events
) 是一种单向通信协议,服务器可以通过 HTTP
持久连接主动向客户端推送数据。相比 WebSocket
,SSE
实现简单,适用于只需要单向消息推送的场景。
SSE
服务端工作流: 1. 在服务端,我们需要设置 HTTP
响应头, 告诉客户端这是一个事件流, 设置响应头: Content-Type: text/event-stream
、Cache-Control: no-cache
禁用缓存、Connection: keep-alive
保持长连接; 2.关闭自动响应处理, 比如 Koa
需要设置 ctx.respond = false
, 否则, Koa
可能在你的写操作完成之前结束响应,导致连接中断,从而触发 error
事件; 3. 生成消息之后, 通过 ctx.res.write(data)
发送数据,并注意数据格式必须符合 SSE
规范(每条消息以 data:
开头,以两个换行符 \n\n
结束); 4. 保持连接并在客户端断开时清理定时器等资源。当客户端关闭连接时,通过 ctx.req.on('close', ...)
清理定时器,防止内存泄露。
SSE
客户端工作流:
-
基于
Fetch
接收流式数据: 1. 请求初始化, 使用fetch
发起POST
请求,传入JSON
格式的body
,并设置Content-Type
请求头, 通过AbortController
来获取signal
, 方便后续取消请求; 2. 流式接收处理, 在获取响应后,判断response.ok
,否则抛出错误。从response.body
获取一个ReadableStream
的reader
,通过reader.read()
进入一个异步循环。每次读取到数据块后,使用TextDecoder
将二进制数据解码为字符串,然后直接处理(如检查是否包含data:
前缀,或是否为[DONE]
标记)。3. 请求结束处理, 当reader.read()
返回done
为true
或遇到[DONE]
标记时,结束循环并调用close()
。4. 提供close
方法, 调用controller.abort
中断请求, 关闭连接。基于Fetch
接收流式数据 可以发送Post
请求, 处理流数据相比于XMLRequestHttp
比较方便。 -
基于
EventSource
接收流式数据: 一个EventSource
实例会对HTTP
服务器开启一个持久化的连接, 以text/event-stream
格式发送事件,此连接会一直保持开启直到通过调用EventSource.close()
关闭。与WebSocket
不同的是, 服务器发送事件是单向的。数据消息只能从服务端到发送到客户端(如用户的浏览器)。工作流为: 1. 请求初始化, 直接创建EventSource
对象,传入目标URL
(注意SSE
默认使用GET
请求,且请求参数通过URL
查询字符串传递)。2. 流式接收处理,onopen
事件连接建立成功时,更新状态为connected
,onmessage
, 浏览器自动解析服务端以SSE
格式发送的数据,调用该回调, 每收到一条消息,就检查event.data
, 如果为[DONE]
则关闭连接, 否则, 直接调用onMessage
。4. 提送close
方法, 调用eventSource.close
关闭链接, 终端请求。基于EventSource
接收流式数据 只支持Get
请求, 发送的数据有长度限制。 -
基于
XMLRequestHttp
接收流式数据: 1. 请求初始化, 创建XMLHttpRequest
对象,调用open("POST", url, true)
初始化异步POST
请求,并设置请求头(Content-Type: application/json
)(请求头随意)。2. 通过send()
发送请求。3. 流式接收处理, 每当收到部分响应时,会触发onprogress
事件, 此时, 根据responseText
的长度与之前记录的lastIndex
,提取出新增的数据, 将新增数据累加到一个内部buffer
中,然后以换行符分割,处理分割出来的完整数据块, 对每个数据块做trim
处理,并检查是否以data:
开头,如果是则去掉data:
前缀后传给onMessage
回调, 对于[DONE]
标记,则结束接收并调用close()
终止请求。4. 请求结束处理, 在onreadystatechange
回调中, 当readyState
为DONE
时(即请求完成),如果状态码不为200
,则调用onError
通知错误,否则处理buffer
中残留的部分数据。5. 提供close
方法, 调用xhr.abort
终端请求, 关闭长连接。基于XMLRequestHttp
接收流式数据 流数据处理需要手动管理buffer
与分块处理,代码较繁琐, 错误处理与状态判断较为分散。