SSE(Server-Sent Events)的使用

前言

说真的,有些技术就像工具箱里那把不起眼的螺丝刀,不用到拧螺丝那天,你永远不知道它比电钻还好使。

之前总听人说 SSE(Server-Sent Events,服务器推送),但一直没啥机会上手,直到上个月接了个坐席系统:坐席和客户打电话时,系统得像ChatGPT那样,边说边把语音转成文字弹出来,还不能卡顿

当时第一反应是"这简单啊,直接上WebSocket呗",结果被后端老哥怼了:"咱项目里已经有两个模块在用WebSocket了,现在再加一个?再开怕不是要被运维拉进黑名单!"

那就退而求其次,用轮询?结果一算账更崩溃:假设500ms轮询一次,一个坐席一天接200通电话,每通平均10分钟,光转文字接口就要被轮24万次!这服务器不得直接跪?

这时候,我突然想起 SSE 不就十分契合当前场景嘛,接下来我们就一起了解一下 SSE 吧。

SSE 介绍

**SSE(Server-Sent Events)**是一种基于HTTP协议的服务器推送技术,允许服务器主动向客户端(如浏览器)单向推送实时数据,适用于需要服务器单向实时通信的场景。

SSE 优点

1. 简单易用

  • 协议简单:基于普通 HTTP/HTTPS 协议,无需特殊协议
  • API 简洁 :浏览器端使用 EventSource API,几行代码即可实现
  • 自动重连:内置断线重连机制

2. 单向服务器推送

  • 实时性好:服务器可以随时推送新数据
  • 低延迟:相比轮询方式,减少了不必要的请求

3. 轻量级

  • 开销小:相比 WebSocket,协议头更简单
  • 兼容性好:基于 HTTP,更容易通过防火墙和代理

4. 功能完善

  • 支持事件类型:可以发送不同类型的事件
  • 内置消息ID:支持断线后恢复,避免消息丢失
  • 自动UTF-8解码:处理文本数据更方便

SSE 缺点

1. 功能限制

  • 仅支持文本:不能直接传输二进制数据
  • 单向通信:只能服务器→客户端,不能客户端→服务器
  • 无压缩:HTTP 头部不支持压缩

2. 浏览器限制

  • 连接数限制:浏览器对同一域名下的并发 SSE 连接数有限制(通常6个)
  • 旧版IE不支持:IE/Edge 旧版本不支持,需要 polyfill

3. 服务器实现

  • 保持连接:服务器需要维护长连接,可能增加负担
  • 超时处理:需要正确处理连接超时和断开

4. 其他限制

  • Cookie限制:某些浏览器在SSE中不会发送Cookie
  • 代理问题:某些代理服务器可能缓冲SSE流
  • 请求头限制 :浏览器的原生支持EventSource不支持配置请求头

兼容性

图片来自 EventSource - Web API | MDN

浏览器 API - EventSource

实例属性

readyState

表明连接的当前状态,该属性只读,有三个属性

  • 0:connecting 连接还没有建立或者重连中
  • 1:open 连接已经建立
  • 2: close 连接已断开

withCredentials

一个布尔值,表示 EventSource 对象是否使用跨源资源共享凭据(cookie)来实例化(true),或者不使用(false,即默认值)

ps:关闭连接的话调用实例的 close 方法就行。

使用示例

js 复制代码
if ('EventSource' in window) {

    // 创建 EventSource 对象连接服务器,并携带 cookie
    const eventSource = new EventSource('/sse-endpoint', { withCredentials: true });
    
    // `0` --- connecting `1` --- open // `2` --- close
    console.log(sse.readyState)

    // 连接成功回调
    eventSource.onopen = function (event) {
      console.log('连接成功:');
    };


    // 监听消息事件
    eventSource.onmessage = function(event) {
      console.log('收到消息:', event.data);
      // 消息结束通知
      if(event.data.done) {
        eventSource.close() // 关闭sse连接
      }
    };

    // 监听自定义事件
    eventSource.addEventListener('customEvent', function(event) {
      console.log('自定义事件:', event.data);
    });

    // 错误处理
    eventSource.onerror = function(error) {
      console.error('SSE 错误:', error);
    };
} else {
    console.log('当前浏览器不支持 EventSource')
}

使用中遇到的问题

浏览器原生的实现不能更改请求头 ,解决办法:使用 fetch 模拟实现,或者使用第三方库:event-source-polyfill@microsoft/fetch-event-source

服务端(node.js)示例

js 复制代码
const http = require('http');

http.createServer((req, res) => {
  if (req.url === '/sse-endpoint') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    });
    
    // 发送初始消息
    res.write('data: 连接已建立\n\n');
    
    // 定时发送消息
    let counter = 0;
    const interval = setInterval(() => {
      counter++;
      res.write(`data: 这是消息 ${counter}\n\n`);
      
      // 发送自定义事件
      if (counter % 3 === 0) {
        res.write(`event: customEvent\n`);
        res.write(`data: 这是自定义事件消息 ${counter}\n\n`);
      }
      
      // 测试结束连接
      if (counter === 10) {
        res.write('event: close\n');
        res.write('data: 连接即将关闭\n\n');
        clearInterval(interval);
        res.end();
      }
    }, 1000);
    
    // 客户端断开连接时清理
    req.on('close', () => {
      clearInterval(interval);
      res.end();
    });
  } else {
    res.writeHead(404);
    res.end();
  }
}).listen(3000);

console.log('SSE 服务器运行在 http://localhost:3000');

总结

说到底,技术从来不是孤立的炫技场,而是业务场景的"最佳拍档"。就像给不同身材的人挑衣服,SSE这匹快马就该用在实时消息推送这类"长跑赛道"上,而AI对话、语音转写这些需要双向奔赴的场景,正是它大显身手的地方。选技术就像点菜,不追求满汉全席,能把业务这桌菜烧出滋味,就是真功夫。

博客主要记录一些学习的文章,如有不足,望大家指出,谢谢。

相关推荐
2501_920931702 小时前
React Native鸿蒙跨平台采用ScrollView的horizontal属性实现横向滚动实现特色游戏轮播和分类导航
javascript·react native·react.js·游戏·ecmascript·harmonyos
0思必得03 小时前
[Web自动化] Selenium处理动态网页
前端·爬虫·python·selenium·自动化
东东5164 小时前
智能社区管理系统的设计与实现ssm+vue
前端·javascript·vue.js·毕业设计·毕设
catino4 小时前
图片、文件的预览
前端·javascript
测试涛叔5 小时前
金三银四软件测试面试题(800道)
软件测试·面试·职场和发展
2501_920931705 小时前
React Native鸿蒙跨平台实现推箱子游戏,完成玩家移动与箱子推动,当所有箱子都被推到目标位置时,玩家获胜
javascript·react native·react.js·游戏·ecmascript·harmonyos
layman05286 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔6 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李6 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN6 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化