导读:本期聚焦于重启一下创作的《AI流式输出该用SSE还是WebSocket?Server-Sent Events与WebSocket选型对比与代码实现》,敬请观看详情。大模型逐字吐出回答的背后,到底该选SSE还是WebSocket?不少人在做AI对话功能时都会纠结这个问题。本文从协议原理出发,对比SSE基于HTTP单向推送与WebSocket全双工通信的差异,分析Token流式返回、断线重连、连接数限制、代理兼容性等关键指标,并分别给出服务端与前端浏览器的完整实现代码,最后结合ChatGPT类产品的主流做法,帮你判断哪种方案更适合流式输出场景,少走弯路。

做AI对话产品的人几乎都绕不开一个问题:模型逐字输出的效果,到底是用SSE推送还是用WebSocket长连接?有人觉得WebSocket功能更强就无脑选它,也有人发现主流大模型API(比如OpenAI的Chat接口)清一色用的都是SSE,又搞不清原因。这两种方案各有明确的适用边界,选错了不仅浪费服务器资源,还可能踩上一堆代理转发、断线重连的坑。这篇文章把两者的协议原理、实现代码和选型逻辑讲清楚。

AI流式输出该用SSE还是WebSocket?Server-Sent Events与WebSocket选型对比与代码实现

一、先搞清楚两者的协议本质差异

SSE(Server-Sent Events)本质上还是一个普通的HTTP响应,只是响应头里带了Content-Type: text/event-stream,并且连接不主动关闭,服务端可以持续往响应体里写数据。它是严格单向的:只能服务端推给客户端,客户端想发消息就得另起一个普通的HTTP请求。而WebSocket是在HTTP握手之后通过Upgrade头升级成的一个独立协议,升级完成后连接变成全双工的TCP通道,双方都可以随时主动发数据,不再受HTTP请求-响应模型的约束。

这个本质差异决定了两者的能力边界。SSE走的是标准HTTP端口(80/443),所以经过Nginx反向代理、CDN、企业防火墙时基本不会出问题,只需要注意关闭代理的响应缓冲即可。WebSocket虽然也走80/443端口,但握手阶段的Upgrade请求经常被一些老旧的代理或者未正确配置的Nginx拦下来,报出奇怪的错误。另外,浏览器的EventSource API原生支持断线自动重连和Last-Event-ID续传,WebSocket断了就得自己写重连逻辑和消息补发机制。

还有一个容易被忽视的点:连接数限制。基于HTTP/1.1的SSE,浏览器对同一域名只允许6个并发连接,如果用户开了多个标签页同时接收流式输出,就可能占满连接池导致页面其他请求卡死。不过只要服务端启用了HTTP/2,多个SSE连接会复用同一条TCP连接,这个问题就自然消失了。WebSocket没有这个限制,每个连接都是独立的。

二、各自怎么实现:服务端与前端完整代码

1. SSE的服务端与浏览器端实现

SSE的数据格式非常简单,每条消息由若干行组成,字段之间用空行分隔,data:后面是消息体。下面用Node.js演示一个模拟大模型逐字输出的服务端:

// Node.js 原生实现 SSE
const http = require('http');

http.createServer((req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  const answer = '你好,我是AI助手,这是一段流式输出的回答。';
  let i = 0;

  const timer = setInterval(() => {
    if (i < answer.length) {
      // 每次推送一个字符,data:开头,双换行结束
      res.write(`data: ${JSON.stringify({ token: answer[i] })}\n\n`);
      i++;
    } else {
      // 发送结束标记后关闭连接
      res.write('data: [DONE]\n\n');
      res.end();
      clearInterval(timer);
    }
  }, 50);

  // 客户端断开时清理定时器
  req.on('close', () => clearInterval(timer));
}).listen(3000);

浏览器端用原生的EventSource就够了,不需要引入任何库:

const es = new EventSource('http://127.0.0.1:3000/chat');

es.onmessage = (e) => {
  if (e.data === '[DONE]') {
    es.close(); // 输出完成,主动关闭
    return;
  }
  const { token } = JSON.parse(e.data);
  document.getElementById('output').textContent += token;
};

es.onerror = () => {
  // EventSource 会自动重连,这里可以更新界面提示
  console.log('连接中断,正在自动重连...');
};

如果需要携带自定义请求头(比如鉴权的Authorization),原生EventSource做不到,可以改用fetch配合ReadableStream读取,这也是目前很多AI产品前端的做法,因为fetch还能在需要时用AbortController随时中断生成。

2. WebSocket的实现

WebSocket适合的是多轮交互、语音输入这种客户端也要高频发消息的场景。以Python的websockets库为例:

import asyncio, json, websockets

async def handle(ws):
    # 先接收用户的问题(客户端可以随时发)
    async for message in ws:
        question = json.loads(message)['text']
        answer = f'关于{question}的回答,逐字返回给你。'
        for ch in answer:
            await ws.send(json.dumps({'token': ch}, ensure_ascii=False))
            await asyncio.sleep(0.05)
        await ws.send(json.dumps({'done': True}))

async def main():
    async with websockets.serve(handle, '0.0.0.0', 8765):
        await asyncio.Future()  # 永久运行

asyncio.run(main())

前端对应代码:

const ws = new WebSocket('ws://127.0.0.1:8765');

ws.onopen = () => ws.send(JSON.stringify({ text: '什么是SSE' }));

ws.onmessage = (e) => {
  const data = JSON.parse(e.data);
  if (data.done) { ws.close(); return; }
  document.getElementById('output').textContent += data.token;
};

// 注意:WebSocket 断线不会自动重连,必须自己处理
ws.onclose = () => console.log('连接已关闭');

三、AI流式场景到底该怎么选

回到最初的问题。大模型API几乎清一色选择SSE,不是偶然的。AI对话的数据流向有非常明显的特征:请求阶段用户发一次问题(一个普通POST请求就够了),响应阶段模型逐Token往外吐。整个过程只需要服务端单向推送,WebSocket引以为傲的全双工能力在这里完全用不上,反而要多付出协议升级、心跳保活、重连状态管理的复杂度。

SSE的优势在这个场景下被放大到极致:基础设施兼容性好,不需要改Nginx配置去支持Upgrade;浏览器自动重连;服务端实现成本极低,甚至一个普通的Servlet、PHP脚本都能做流式输出。对于"用户提问、AI流式回答"这一类典型交互,直接选SSE,没有第二个答案。

但WebSocket也有它不可替代的场景。第一是实时语音对话,客户端要持续上传音频流,同时接收服务端返回的音频和字幕,双向都是高频流,SSE根本撑不住。第二是协同类AI应用,比如多人同时在一个画布上和AI交互,消息广播、状态同步都需要双向通道。第三是长会话多轮交互,如果每次提问都重建HTTP连接开销太大,一条持久的WebSocket连接反而更省资源。

实际的工程实践中还有一条折中路线值得参考:主体走SSE做流式输出,同时保留一个普通HTTP接口处理用户的打断、重新生成等操作。这样既享受了SSE的简单可靠,又解决了单向通道无法中途干预的问题,很多开源的ChatGPT类项目(如LobeChat)早期就是这么做的。

总结一句:纯流式输出选SSE,双向实时交互选WebSocket,混合需求可以考虑SSE加普通接口的组合。选型时别被WebSocket的"功能强大"迷惑,协议越简单,运维成本越低,出问题的概率也越小。

SSEWebSocketAI流式输出修改时间:2026-09-04 20:54:40

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/50476.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。