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对话、语音转写这些需要双向奔赴的场景,正是它大显身手的地方。选技术就像点菜,不追求满汉全席,能把业务这桌菜烧出滋味,就是真功夫。

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

相关推荐
万事胜意5073 分钟前
前端切换Tab数据缓存实践
前端
渣渣宇a4 分钟前
Three_3D_Map 中国多个省份的组合边界绘制,填充背景
前端·javascript·three.js
点正7 分钟前
ResizeObserver 和nextTick 的用途
前端
狗子的狗粮9 分钟前
Node.js 模块加载与 exports 和 module.exports 的区别
javascript
zayyo9 分钟前
Web 应用轻量化实战
前端·javascript·面试
kovli13 分钟前
红宝书第十七讲:通俗详解JavaScript的Promise与链式调用
前端·javascript
lilye6614 分钟前
精益数据分析(19/126):走出数据误区,拥抱创业愿景
前端·人工智能·数据分析
李是啥也不会19 分钟前
Vue中Axios实战指南:高效网络请求的艺术
前端·javascript·vue.js
xiaoliang24 分钟前
《DNS优化真经》
前端
一只小海獭27 分钟前
了解uno.config.ts文件的配置项---转化器
前端