服务端持续推送数据,SSE究竟怎样工作

举报
yd_232671198 发表于 2026/11/06 10:38:03 2026/11/06
【摘要】 SSE 适合任务进度、通知等服务器单向推送场景。本文介绍事件格式、EventSource 的连接管理、断线重连与补发、代理缓冲和身份验证,并说明如何验证数据是否逐段到达及恢复后是否缺失或重复。

任务执行进度、通知列表、逐段生成的文字,都有一个共同点:服务器会持续产生新数据,浏览器需要及时显示。如果每隔一秒发一次查询请求,既会产生空轮询,也很难让更新足够连贯。

这类以服务器向浏览器推送为主的场景,可以考虑 SSE,也就是 Server-Sent Events。浏览器发起一个 HTTP 请求,服务器保持响应打开,并按规定的文本格式不断写入事件。它主要解决单向推送;客户端需要提交指令时,仍然可以使用普通 HTTP 请求。

SSE 响应使用 text/event-stream,内容按 UTF-8 编码。一个事件以空行结束,格式可以是:

id: 1042
event: update
data: {"text":"任务已经完成一半"}

其中 event 指定事件类型,data 是数据,id 是服务器分配的事件标识。一个事件可以有多行 data,浏览器会把它们用换行连接。不要把任意一次网络读取到的字节块当成完整事件:网络分块可能拆开一行,甚至拆开一个中文字符。

如果使用浏览器内置的 EventSource,这些解析工作由浏览器完成:

const stream = new EventSource('/api/events');

stream.addEventListener('update', event => {
  try {
    const value = JSON.parse(event.data);
    if (typeof value.text === 'string') {
      document.querySelector('#progress').textContent = value.text;
    }
  } catch {
    console.warn('收到无法解析的推送数据');
  }
});

stream.onerror = () => {
  // 临时断线时通常会自动重连,不要在这里反复创建新连接。
  console.warn('推送连接异常,等待恢复');
};

// 页面组件销毁或用户结束订阅时调用 stream.close()。

示例假定页面存在 progress 元素,且服务端确实发送 update 类型事件。如果没有指定事件类型,应通过 message 监听。某些任务的“业务错误”也需要单独定义事件,不能把连接层的异常和任务执行失败混为一谈。

EventSource 具有自动重连能力,但自动重连不等于自动恢复所有数据。在符合重连条件时,浏览器会尝试恢复连接;已有事件标识时,会通过 Last-Event-ID 传给服务端。服务器必须维护可追溯的事件序列,并根据这个标识补发遗漏内容,断线期间的数据才有机会恢复。

事件历史不能无限保存,因此还需要约定过期处理。例如客户端提供的标识已经早于保留范围,服务端可以发送“需要重新同步”的业务事件,让页面重新取得完整状态。客户端也应能按事件标识处理可能出现的重复内容,不能默认每条消息只会出现一次。

在网关或反向代理之后,还要检查响应缓冲和空闲超时。应用程序虽然逐段写入,代理如果一直攒着不发,浏览器看到的仍然会是一大段延迟结果。可以根据实际服务器配置关闭相关缓冲,并定期发送以冒号开头的注释心跳。心跳能减少空闲断开,但无法保证绕过所有平台的连接时长限制。

身份验证也有约束。原生 EventSource 主要发起 GET 请求,不能像 fetch 一样随意添加自定义认证头。可以按业务使用安全的 Cookie 会话;跨来源携带凭证时,还要正确配置 CORS 和 Cookie 策略。不要为了方便就把长期访问令牌放到 URL 中,它可能进入日志和历史记录。

验证时,应检查响应是否真正逐段到达,再主动断网,观察恢复后是否缺消息、是否重复。还要通过真实网关测试,而不仅是在本地直连应用。SSE 的接口很短,可靠使用却依赖事件边界、连接管理和服务端补发这几件具体工作。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。