基于SSE实现AI聊天场景的流式输出

什么是SSE

SSE(Server-Sent Events),轻量级单向实时通信技术,专为 "服务器向客户端持续推送流式数据" 而设计。

SSE本质是客户端发送一个普通的HTTP请求,服务器保持连接打开,然后持续不断地向客户端推送数据。

  • 普通http:一次请求 -> 一次响应 -> 连接关闭
  • SSE:一次请求 -> 多次响应 -> 连接长期保持

SSE的特点

  1. 单向通信:只支持服务器->客户端推送,不支持客户端通过SSE向服务器发送数据
  2. 自动重连:浏览器原生支持,无需手动实现
  3. 断点续传:通过Last-Event-ID头,断线重连后可以从上次断开的位置继续接收数据
  4. http原生支持
  5. 多个SSE可以共享一个TCP连接,降低服务器开销

基于以上特点,SSE是目前AI聊天、日志监控等场景的首选方案。

工作步骤

步骤:

  1. 连接建立
  2. 服务器响应
  3. 数据推送
  4. 连接关闭

连接建立

客户端通过EventSource对象向服务器发送一个http GET请求,请求头中有Accept: text/event-stream

vbnet 复制代码
GET /api/chat HTTP/1.1
Host: example.com
Accept: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

服务器响应

yaml 复制代码
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Transfer-Encoding: chunked

数据推送

数据必须遵循SSE标准格式

yaml 复制代码
id: 123
event: message
data: 这是第一条消息

data:这是第二条消息
这还是第二条消息

retry: 5000

id: 消息id,可选,用于断点续传 event:自定义事件类型,默认是message data: 消息内容,可以跨多行 retry: 断线重连间隔多少ms

豆包网页版的SSE截图:

代码实现

前端示例

ts 复制代码
window.mockChat = () => {
  // 创建SSE连接
  const eventSource = new EventSource('http://localhost:3000/api/chat?prompt=你好')

  // 监听默认message事件
  eventSource.onmessage = (e) => {
    console.log('收到消息:', e.data)
  }

  // 监听自定义事件
  eventSource.addEventListener('complete', (e) => {
    console.log('回答生成完成')
    eventSource.close() // 关闭连接
  })

  // 监听错误事件
  eventSource.onerror = (e) => {
    // @todo
  }
}

服务端示例

js 复制代码
import express from 'express'

const app = express()

app.get('/api/chat', (req, res) => {
  // 设置SSE响应头
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
    'Access-Control-Allow-Origin': '*',
  })

  // 模拟大模型流式生成回答
  const answer = '你好,我是AI助手,很高兴为你服务!'
  let index = 0

  const timer = setInterval(() => {
    if (index < answer.length) {
      // 每次发送一个字
      res.write(`data: ${answer[index]}\n\n`)
      index++
    } else {
      // 发送完成事件
      res.write('event: complete\n')
      res.write('data: done\n\n')
      clearInterval(timer)
      res.end()
    }
  }, 100)

  // 客户端关闭连接时清理资源
  req.on('close', () => {
    clearInterval(timer)
    console.log('客户端断开连接')
  })
})

app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000')
})

效果截图

SSE和WebSocket的对比

对比维度 SSE (Server-Sent Events) WebSocket
协议基础 纯 HTTP/HTTPS 协议 GET 请求 独立的 WebSocket 协议
通信方向 单向:仅服务器→客户端推送 全双工:客户端↔服务器双向自由发送
数据格式 仅支持文本数据(UTF-8),内置事件流格式 支持二进制和文本数据,无内置格式,完全自定义
自动重连 浏览器原生支持,断线后自动重连 无原生支持,需要手动实现重连、心跳、退避算法
兼容性 所有现代浏览器支持,IE10+ 所有现代浏览器支持,IE10+
CDN / 代理支持 完美支持,可利用 CDN 缓存、边缘计算 较差,多数 CDN 不支持 WebSocket 代理
性能开销 极低,HTTP/2 支持多路复用,多个 SSE 连接共享一个 TCP 连接 中等,每个 WebSocket 连接独占一个 TCP 连接

最后

SSE 是一种轻量级、简单、可靠的实时通信技术,它没有 WebSocket 那么强大,但在 "大模型一次请求,流式响应" 这个业务场景下,它是简单、成本低、兼容性最好的选择。

相关推荐
Bigger6 小时前
mini-cc 技术栈:跟着 Claude Code 先选 TypeScript + React + Ink
前端·ai编程·claude
vortex57 小时前
XSS 漏洞深度挖掘与利用:从自动化扫描到账户接管
前端·自动化·xss
CHEN5_027 小时前
Agent开发基础概念
agent·ai编程
光影少年7 小时前
前端浏览器自动化
运维·前端·前端框架·自动化
弹简特7 小时前
【Vue3速成】04-vue3官方库-路由机制
前端·vue·路由
麦哲思科技任甲林7 小时前
写个缺陷修复的skill,提高AI的缺陷修复效率
ai编程·缺陷修复
threelab7 小时前
Three.js 抽象艺术着色器效果 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
萌新小码农‍7 小时前
Python的input函数
java·前端·python
No8g攻城狮7 小时前
【AI工具】Sub2API简介 – 开源 AI API 中转网关平台,支持多账户管理
人工智能·ai·开源·ai编程