跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptNode.jsAI大前端

前端 SSE 技术详解:从原理到 AI 流式对话实战

SSE 是一种基于 HTTP 的服务器推送协议,适用于实时通知与流式数据场景。深入解析其单向通信机制,对比原生 EventSource 与 fetch + ReadableStream 两种前端实现方案,重点演示如何结合 Node.js 后端构建 AI 对话流式输出功能。涵盖数据格式处理、断线重连、错误管理及性能优化策略,帮助开发者在 Web 应用中高效集成实时通信能力。

王初壹发布于 2026/4/11更新于 2026/9/971 浏览

什么是 SSE

SSE(Server-Sent Events)是一种服务器向客户端推送数据的技术,它允许服务器主动向客户端发送数据,而不需要客户端频繁轮询。SSE 特别适合实时通信场景,比如AI 聊天的流式输出、实时通知、股票行情更新等。

SSE 的核心特点
  • 单向通信:服务器向客户端单向推送
  • 基于 HTTP:使用标准 HTTP 协议,无需特殊服务器支持
  • 自动重连:连接断开时会自动尝试重连
  • 文本格式:使用简单的文本格式传输数据
  • 轻量级:实现简单,开销小

SSE 的工作原理

1. 连接建立

客户端通过向服务器发送一个 HTTP 请求来建立 SSE 连接。服务器返回一个特殊的响应,设置 Content-Type: text/event-stream 头,告诉客户端这是一个 SSE 流。

2. 数据传输

服务器以流的形式持续发送数据,每个数据块都是一个 SSE 格式的消息。SSE 消息格式如下:

data: 消息内容\n\n 

其中:

  • data: 是固定前缀
  • 消息内容可以是任意文本,通常使用 JSON 格式
  • \n\n 是消息结束标志

3. 客户端处理

客户端接收并解析流式数据,根据消息内容进行相应处理。在浏览器中,可以使用 EventSource API 或 fetch + ReadableStream 来处理 SSE。

前端实现 SSE 的两种方式

方式一:使用原生 EventSource API

EventSource 是浏览器内置的 SSE 客户端 API,使用非常简单:

const sse = new EventSource('/api/stream');
sse.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    console.log('收到数据:', data);
});
sse.addEventListener('error', (event) => {
    console.error('SSE 错误:', event);
});

注意:EventSource 只支持 GET 请求,无法发送 POST 数据。

方式二:使用 fetch + ReadableStream

当需要向服务器发送 POST 数据时(比如发送用户输入到 AI 模型),可以使用 fetch + ReadableStream 来模拟 SSE:

const response = await fetch('/api/stream-chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userInput: inputText })
});

if (!response.ok) throw new Error(`HTTP 错误:${response.status}`);
if (!response.body) throw new Error("响应体不可用");

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n\n');
    buffer = lines.pop() || '';
    for (const line of lines) {
        if (!line.startsWith('data: ')) continue;
        const dataStr = line.slice(6);
        const data = JSON.parse(dataStr);
        // 处理数据...
    }
}

实战:AI 聊天的流式输出实现

1. 后端实现(Express + LangChain)

app.post('/api/stream-chat', async (req, res) => {
    try {
        const { userInput } = req.body;
        if (!userInput) return res.status(400).json({ error: "用户输入不能为空" });

        // 设置 SSE 响应头
        res.setHeader('Content-Type', 'text/event-stream');
        res.setHeader('Cache-Control', 'no-cache');
        res.setHeader('Connection', 'keep-alive');
        res.flushHeaders();

        // 调用 AI 模型生成回复
        const stream = await model.stream(`用户提问:${userInput},请用简洁的语言回复`);

        // 逐块发送 AI 输出
        for await (const chunk of stream) {
            res.write(`data: ${JSON.stringify({ content: chunk?.content || chunk })}\n\n`);
        }

        // 发送结束标识
        res.write(`data: ${JSON.stringify({ done: true })}\n\n`);
        res.end();
    } catch (err) {
        console.error('Error in stream-chat:', err);
        res.write(`data: ${JSON.stringify({ error: err?.message || '服务器内部错误' })}\n\n`);
        res.end();
    }
});

2. 前端实现(fetch + ReadableStream)

// 发送请求
const response = await fetch('http://localhost:8000/api/stream-chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userInput: inputText })
});

// 检查响应
if (!response.ok) throw new Error(`HTTP 错误:${response.status}`);
if (!response.body) throw new Error("响应体不可用");

// 创建读取器和解码器
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

// 处理流式数据
while (isStreaming) {
    const { done, value } = await reader.read();
    if (done) break;

    // 解码并处理 SSE 格式数据
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n\n');
    buffer = lines.pop() || '';

    // 处理每一条消息
    for (const line of lines) {
        if (!line.startsWith('data: ')) continue;
        const dataStr = line.slice(6);
        const data = JSON.parse(dataStr);

        // 处理错误信息
        if (data.error) {
            aiMsgElement.textContent = `错误:${data.error}`;
            isStreaming = false;
            break;
        }

        // 处理结束标识
        if (data.done) {
            isStreaming = false;
            break;
        }

        // 逐字显示 AI 回复
        aiMsgElement.textContent += data.content;
    }
}

SSE 实现的关键技术点

1. 数据格式处理

SSE 使用简单的文本格式,每个消息以 data: 开头,以 \n\n 结束。前端需要:

  • 正确解析这种格式
  • 处理可能分块到达的数据(使用缓冲区)
  • 处理不完整的消息(保留到缓冲区)

2. 流式数据读取

使用 ReadableStream API 读取流式数据:

  • getReader():创建读取器
  • read():异步读取数据块
  • done:标识流是否结束
  • value:当前数据块(二进制)

3. 文本解码

使用 TextDecoder API 将二进制数据转换为字符串:

  • decode(value, { stream: true }):流式解码,支持分块处理

4. 错误处理

需要处理多种错误情况:

  • HTTP 错误(响应状态码非 200)
  • 响应体不可用
  • JSON 解析错误
  • 网络中断

5. 状态管理

需要管理流式处理的状态:

  • isStreaming:控制是否继续处理数据
  • 停止按钮:允许用户手动中断流式传输
  • 状态重置:流式结束后恢复 UI 状态

SSE vs WebSocket

特性SSEWebSocket
通信方向单向(服务器→客户端)双向
协议HTTPWebSocket
实现复杂度低高
自动重连支持需手动实现
数据格式文本(通常 JSON)二进制或文本
跨域支持支持(CORS)需特殊配置
适用场景实时通知、流式输出实时聊天、游戏

SSE 的优缺点

优点

  1. 实现简单:基于 HTTP,不需要特殊的服务器支持
  2. 自动重连:浏览器会自动处理重连
  3. 轻量级:开销小,适合简单的实时场景
  4. 兼容性好:支持所有现代浏览器
  5. 易于调试:使用标准 HTTP 工具即可调试

缺点

  1. 单向通信:只能服务器向客户端推送
  2. 数据格式限制:只能传输文本数据
  3. 连接数限制:浏览器对同一域名的连接数有限制
  4. 不支持二进制数据:需要转换为文本格式

适用场景

SSE 特别适合以下场景:

  1. AI 聊天的流式输出:实时显示 AI 生成的回复
  2. 实时通知:系统通知、消息提醒
  3. 实时数据更新:股票行情、天气数据
  4. 日志流:实时查看服务器日志
  5. 监控数据:系统状态、性能指标

代码优化建议

1. 错误处理增强

try {
    // 现有代码...
} catch (error) {
    // 显示错误信息
    aiMsgElement.textContent += `\n(出错:${error.message})`;
    // 在控制台输出错误
    console.error("流式接收错误:", error);
    // 重置状态
    isStreaming = false;
    sendBtn.disabled = false;
    stopBtn.style.display = 'none';
}

2. 性能优化

// 对于大型消息,使用 DocumentFragment 减少 DOM 操作
const fragment = document.createDocumentFragment();
const tempElement = document.createElement('div');

// 处理数据时先更新临时元素
tempElement.textContent += data.content;

// 定期更新 DOM(比如每 100ms)
if (Date.now() - lastUpdateTime > 100) {
    aiMsgElement.textContent = tempElement.textContent;
    lastUpdateTime = Date.now();
}

3. 用户体验优化

// 添加加载动画
aiMsgElement.innerHTML = '<div class="loading">生成中...</div>';

// 流式结束后移除加载动画
if (data.done) {
    aiMsgElement.innerHTML = aiMsgElement.textContent;
    isStreaming = false;
    break;
}

总结

SSE 是一种简单高效的服务器向客户端推送数据的技术,特别适合实时流式输出场景。通过本文的介绍,你应该已经了解了:

  1. SSE 的基本概念和工作原理
  2. 前端实现 SSE 的两种方式
  3. 如何实现 AI 聊天的流式输出
  4. SSE 的优缺点和适用场景
  5. 代码优化的建议

SSE 虽然简单,但功能强大,是实时 Web 应用的重要工具之一。在实际开发中,根据具体需求选择合适的实时通信方案,才能达到最佳效果。

目录

  1. 什么是 SSE
  2. SSE 的核心特点
  3. SSE 的工作原理
  4. 1. 连接建立
  5. 2. 数据传输
  6. 3. 客户端处理
  7. 前端实现 SSE 的两种方式
  8. 方式一:使用原生 EventSource API
  9. 方式二:使用 fetch + ReadableStream
  10. 实战:AI 聊天的流式输出实现
  11. 1. 后端实现(Express + LangChain)
  12. 2. 前端实现(fetch + ReadableStream)
  13. SSE 实现的关键技术点
  14. 1. 数据格式处理
  15. 2. 流式数据读取
  16. 3. 文本解码
  17. 4. 错误处理
  18. 5. 状态管理
  19. SSE vs WebSocket
  20. SSE 的优缺点
  21. 优点
  22. 缺点
  23. 适用场景
  24. 代码优化建议
  25. 1. 错误处理增强
  26. 2. 性能优化
  27. 3. 用户体验优化
  28. 总结

更多推荐文章

查看全部
  • Java 网络协议:HTTP 请求与响应
  • Python Mode for Processing 创意编程使用指南
  • HiClaw 开源:Team 版 OpenClaw 本地安装与架构解析
  • SDXL Prompt Styler 工具使用指南:优化 AI 绘画提示词
  • 2026 年主流 AI 大模型实测与选型指南:国产模型崛起与性价比分析
  • MySQL InnoDB 存储引擎:B+树叶子节点能存多少数据?
  • Google Antigravity IDE 介绍:智能体驱动开发体验
  • Whisper.cpp 量化模型清单与 ggml 格式下载指南
  • AI 编程工具深度对比:Cursor、Copilot、Trae 与 Claude Code
  • 【实践】操作系统智能助手OS Copilot新功能测评
  • unstructured:非结构化文档预处理与结构化转换实践
  • 支持 Nor Flash 读写的 SPI 主控制器设计、仿真和 FPGA 验证(含 XIP 模式)
  • Windows Python 安装与环境配置完整教程
  • 26 岁后转行程序员晚吗?毕业学员分享真实经验
  • OpenClaw 本地 AI 助手安装与使用指南
  • 人工智能、机器学习与深度学习的核心概念解析
  • MCP 插件实战:Browser Tools 集成指南
  • 英语学习笔记:认知方法、系统构成与风险管理
  • C++ STL 常用容器实战指南
  • MySQL 迁移至金仓:高兼容自动化与低成本落地实战

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online