大模型流式输出前端实战:ReadableStream+SSE打字机效果全踩坑指南
文章目录一、先唠明白为啥普通接口会让用户干等1.1 开stream前后接口返回天差地别二、ReadableStream浏览器里的数据自来水管2.1 Uint8Array看不懂的数字字节不能直接渲染三、分清两个容易搞混的东西ReadableStream ≠ SSE3.1 缓冲区buffer处理粘包断包的核心3.2 封装SSE事件解析工具函数3.3 完整流式读取循环逻辑四、Vue3页面实时渲染实现打字机效果五、为什么不用原生EventSource非要用Fetch六、SSE vs WebSocket大模型场景怎么选七、后端侧必须配套的能力八、全文总结一条链路记牢P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看传送门https://blog.csdn.net/HHX_01一、先唠明白为啥普通接口会让用户干等咱们平时写的普通HTTP接口逻辑特别死板后端必须等全部内容生成完毕打包完整JSON才丢给前端。之前做AI文案工具踩过超大坑写一篇千字演讲稿模型推理要七八秒。用户界面一片空白后台日志明明在跑产品直接跑过来问我你这页面是不是卡死了更离谱的是有用户以为网站崩了反复刷新直接把接口并发干爆运维找我聊了半小时。流式输出直接把这套逻辑推翻模型每生成一小段文字后端立刻打包发过来前端实时追加展示从根源解决等待焦虑。完整链路一句话概括用户提问 → 模型产出Token → 服务端推送事件 → 浏览器解析数据流 → 页面实时更新。1.1 开stream前后接口返回天差地别没开流式的接口返回一整块完整JSON前端一句response.json()直接解析完事简单到不用动脑子。{choices:[{message:{content:完整回答文字}}]}开启stream之后响应不再是完整对象而是源源不断的碎片化数据流长这样data: {choices:[{delta:{content:你}}]} data: {choices:[{delta:{content:好}}]} data: [DONE]每一段里的delta.content就是新增文字前端不能一次性解析得不停拼接增量内容。二、ReadableStream浏览器里的数据自来水管用fetch请求流式接口后response.body本质就是ReadableStream相当于一根连接后端的水管。刚接触的时候我以为response.body是直接存文字的变量打印出来一看全是ReadableStream对象当场懵了查了半天才明白这只是管道拿不到数据必须装个水龙头。这个水龙头就是getReader()不装水龙头管道里的水一滴都接不出来。基础读取代码长这样constresponseawaitfetch(/api/stream,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({prompt:question.value})});if(!response.body)thrownewError(浏览器不支持流式);constreaderresponse.body.getReader();循环调用reader.read()会返回两个关键值value本次读到的二进制字节数据done布尔值代表数据流是否彻底结束如果后端暂时没发新数据read()会自动等待不用自己写定时器轮询浏览器底层帮我们处理等待逻辑。2.1 Uint8Array看不懂的数字字节不能直接渲染read拿到的value是Uint8Array一堆0-255的纯数字是网络传输的原始字节直接丢页面上全是乱码数字。我第一次没做解码直接把Uint8Array打印到页面满屏都是228、189这种数字测试同事以为我写bug把接口加密了。中文UTF-8字符最少占3个字节网络分片刚好把一个汉字拆成两半不解码直接拼接文字直接乱码成问号。解决办法就是TextDecoder搭配stream:true开启流式解码constdecodernewTextDecoder(utf-8);// 分片解码保留不完整字节consttextdecoder.decode(value,{stream:true});// 流结束后刷新剩余字节bufferdecoder.decode();stream: true是核心解码器会缓存没拼完的字节等下一批数据过来再合并解码完美解决汉字被分片截断的乱码问题。三、分清两个容易搞混的东西ReadableStream ≠ SSE很多新人会把这俩概念混为一谈其实职责完全分开一点不沾边。ReadableStream浏览器读取HTTP响应二进制流的底层API负责接收字节SSE服务端定义的文本事件传输格式规定数据怎么打包、怎么分割。SSE标准格式靠空行分割独立事件每条数据以data:开头大模型接口统一用[DONE]标记传输结束。踩过一个致命误区觉得一次read拿到的数据就是一条完整SSE事件直接JSON.parse结果频繁报语法错误。网络传输不会管你的业务边界一次读取可能拿到半条事件、多条完整事件、或者前一段尾后一段头直接解析百分百报错。3.1 缓冲区buffer处理粘包断包的核心正确处理逻辑必须维护一个字符串缓冲区新解码文本追加到buffer末尾按SSE标准空行分割出完整事件分割后数组最后一段不完整内容重新存回buffer等待下一轮数据拼接关键代码就一行buffer events.pop() ?? ;丢掉这行所有跨分片的文字直接丢失。3.2 封装SSE事件解析工具函数写一个通用解析函数专门提取data内容、识别结束标记、取出增量文字deltafunctionparseSSEEvent(eventText,onDelta){constpayloadeventText.split(/\r?\n/).filter(lineline.startsWith(data:)).map(lineline.slice(5).trimStart()).join(\n);if(!payload)returnfalse;if(payload[DONE])returntrue;constdataJSON.parse(payload);constdeltadata.choices?.[0]?.delta?.content;deltaonDelta(delta);returnfalse;}函数返回true代表数据流传输完毕外层循环直接终止读取。3.3 完整流式读取循环逻辑把流读取、字节解码、SSE解析整合到一个异步函数一次性处理全流程asyncfunctionreadSSEStream(response,onDelta){if(!response.body)thrownewError(无可用流);constreaderresponse.body.getReader();constdecodernewTextDecoder(utf-8);letbuffer;letfinishedfalse;while(!finished){const{value,done}awaitreader.read();if(done){bufferdecoder.decode();break;}bufferdecoder.decode(value,{stream:true});consteventsbuffer.split(/\r?\n\r?\n/);bufferevents.pop()??;for(consteventTextofevents){finishedparseSSEEvent(eventText,onDelta);if(finished)break;}}if(!finishedbuffer.trim())parseSSEEvent(buffer,onDelta);}四、Vue3页面实时渲染实现打字机效果依靠Vue响应式变量每次拿到delta增量直接拼接页面自动更新不用手动操作DOM。之前有人跟我说打字机效果用setInterval模拟就行我试了一次直接放弃。后端要等全文生成完一次性返回弱网下空白十多秒用户流失直接涨纯前端模拟完全是自欺欺人。完整Vue代码示例import { ref } from vue; const question ref(写一篇英语作文); const content ref(); const loading ref(false); async function submit() { if (!question.value || loading.value) return; content.value ; loading.value true; try { const res await fetch(/api/stream, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: question.value }) }); if (!res.ok) throw new Error(请求异常${res.status}); await readSSEStream(res, delta { content.value delta; }); } catch (err) { content.value err.message; } finally { loading.value false; } } {{ loading ? 生成中... : 提交 }} {{ content }} .output { margin-top: 16px; white-space: pre-wrap; } plaintext两个细节注意点CSS添加white-space: pre-wrap保留模型返回的换行、空格格式只用文本插值渲染拒绝v-html防止AI输出内容携带恶意HTML脚本。五、为什么不用原生EventSource非要用FetchEventSource确实原生支持SSE但它有几个硬伤完全不适合AI聊天场景。刚入行的时候图省事直接用EventSource上线才发现它只能发GET请求不能传POST请求体。提问内容、鉴权参数全塞URL里参数一多直接超长报错还没法自定义复杂请求头改接口改了一整晚。AI对话场景刚需POST传参、自定义请求头、主动中断请求、自定义错误捕获FetchReadableStream全部完美支持灵活度拉满。六、SSE vs WebSocket大模型场景怎么选对比维度SSEWebSocket通信方向服务端单向推送客户端、服务端双向互发底层协议基于HTTP长连接独立WebSocket协议数据类型仅文本数据文本、二进制都支持AI文本生成适配度完美适配逻辑简单能实现但代码冗余复杂大模型生成逻辑是前端发一次提问后端持续回文字单向传输足够绝大多数场景SSE性价比更高。只有需要持续双向实时交互的产品才考虑WebSocket。七、后端侧必须配套的能力前端流式能跑通后端BFF层缺一不可绝对不能让前端直接调用大模型原始API。见过有人直接把模型API Key写在VITE环境变量里打包后前端源码明文泄露当天就被爬虫薅走接口产生高额账单。后端标准流程接收前端提问参数服务端存储密钥代理请求大模型接口开启流式传输设置标准SSE响应头持续转发分片数据流给浏览器必备响应头配置Content-Type: text/event-stream; charsetutf-8Cache-Control: no-cacheConnection: keep-alive八、全文总结一条链路记牢AI打字机效果不是前端动画造假是一套完整的字节传输链路LLM生成Token → 后端封装SSE事件 → HTTP分块流 → ReadableStream接收二进制 → Uint8Array字节 → TextDecoder流式解码 → buffer缓存拆分完整事件 → JSON解析delta增量 → Vue响应式实时渲染三个核心边界避坑要点字节边界流式TextDecoder处理中文分片杜绝乱码事件边界buffer缓存不完整SSE片段防止解析报错安全边界密钥存后端BFF前端不暴露任何大模型鉴权信息。搞懂这三层边界不管是Vue、React还是原生JS对接大模型流式接口都不会再踩重复的坑。P.S. 无意间发现了一个巨牛的人工智能教程非常通俗易懂对AI感兴趣的朋友强烈推荐去看看传送门https://blog.csdn.net/HHX_01

相关新闻

049、双管正激的占空比限制

049、双管正激的占空比限制

049 双管正激的占空比限制 从一块冒烟的板子说起 去年帮朋友调试一款48V转12V/20A的通信电源,用的是双管正激拓扑。样机第一次上电,轻载正常,加到10A负载,MOS管炸了,驱动芯片也挂了。拆下来看,两个MOS管的漏源极都短路了,变压器初级绕组有烧焦痕迹。 朋友说:“我算过…

2026/7/23 17:40:51阅读更多 →
使用yolo11训练无人机视角罂粟检测数据集VOC+YOLO格式3648张1类别步骤和流程

使用yolo11训练无人机视角罂粟检测数据集VOC+YOLO格式3648张1类别步骤和流程

【数据集介绍】 注意数据集中存在增强图片主要是旋转增强,占据数据量大约一半,注意查看图片 数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量…

2026/7/23 17:40:51阅读更多 →
048、双管正激变换器原理

048、双管正激变换器原理

048、双管正激变换器原理 上个月帮朋友救一个项目,48V转12V/20A的电源模块,单管正激拓扑,MOS管和续流二极管烧了一轮又一轮。客户催得紧,朋友急得嘴角起泡。我拿到板子一看,复位绕组和漏感尖峰处理得稀碎,MOS管关断瞬间电压应力直接飙到200V+,管子不炸才怪。后来改成双…

2026/7/23 17:40:51阅读更多 →
Java快速上手-环境配置

Java快速上手-环境配置

实际项目开发中java的开发环境主要包含操作系统,jdk,maven,git,ide和mysql数据库.后面的装主要针对windows系统,其它系统将会简单带过. 为方便大家下载,我把所有用到的工具和配置都打包成虚拟硬盘文件,放到网盘中,大家可以在网盘中下载. 网盘地址链接: https://pan.baidu.com/s…

2026/7/23 19:03:05阅读更多 →
2026毕业论文查重率小程序怎么选?实测这5家帮你避坑,学范文稳居榜首

2026毕业论文查重率小程序怎么选?实测这5家帮你避坑,学范文稳居榜首

先看结论:2026年毕业论文查重率赛道,我们实测了市面上主流的小程序/平台,学范文凭借“写作查重降重排版”真一站式闭环排在第一,PaperPass靠海量对比库与出报告速度拿下第二,知网个人查重以高校官方指定背书稳守第三。…

2026/7/23 19:03:05阅读更多 →
小模型自主决策潜力:7B参数下的智能优化实践

小模型自主决策潜力:7B参数下的智能优化实践

1. 项目背景与核心价值 去年我在参与一个智能客服系统优化项目时,发现一个有趣的现象:当我们把大模型生成的回复方案交给小模型执行时,那些参数量在1B以下的小模型经常能给出比预期更灵活的响应。这让我开始系统性研究小模型的"隐藏能力…

2026/7/23 19:03:05阅读更多 →
江西省南昌市龙隐山别墅电梯落地:天井改造土建井道适配偏矮顶层,实用标配款满足轮椅通行长效需求

江西省南昌市龙隐山别墅电梯落地:天井改造土建井道适配偏矮顶层,实用标配款满足轮椅通行长效需求

在江西省南昌市,不少别墅小区都自带室内天井空间,是后装电梯的优质位置,但普遍存在后侧管线梁体不可动、有效尺寸受限的问题;同时部分小区顶层高度偏矮,常规方案容易导致轿厢内部压抑,空间体验大打折扣。对…

2026/7/23 19:03:05阅读更多 →
江西省吉安市吉州区环湖湾别墅电梯:墙角开楼板整改非标土建井道,对重后置布局实现小空间轮椅通行

江西省吉安市吉州区环湖湾别墅电梯:墙角开楼板整改非标土建井道,对重后置布局实现小空间轮椅通行

在江西省吉安市吉州区,不少建成多年的别墅小区都有后装电梯的需求,业主普遍倾向于在室内墙角开楼板做土建井道,但这类后加井道很容易出现上下垂直度偏差、实测尺寸与预报不符的问题,同时非专业施工队的不规范做法(如用…

2026/7/23 19:03:05阅读更多 →
第32讲:实战——I2C传感器极简驱动快速验证

第32讲:实战——I2C传感器极简驱动快速验证

CSDN专栏: 嵌入式程序开发实战嵌入式双范式AI编程嵌入式开发必掌握嵌入式求职面试技术资料 第32讲:实战——I2C传感器极简驱动快速验证 一、I2C传感器驱动基础 I2C是最常用的传感器接口,快速验证I2C传感器驱动是嵌入式开发的基本功。 1.…

2026/7/23 19:01:05阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/23 0:56:31阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/23 0:56:31阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 0:56:31阅读更多 →
Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具

Chitchatter完整指南:免费开源的终极点对点安全聊天工具 【免费下载链接】chitchatter Secure peer-to-peer chat that is serverless, decentralized, and ephemeral 项目地址: https://gitcode.com/gh_mirrors/ch/chitchatter Chitchatter是一款革命性的安…

2026/7/23 0:00:28阅读更多 →
从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表)

更多请点击: https://intelliparadigm.com 第一章:从单点好评到指数级传播:AI副业主理人必须掌握的4层口碑渗透模型(含ROI测算表) 当AI副业主理人不再仅满足于单次服务交付,而是主动构建可复用、可裂变、可…

2026/7/23 0:00:28阅读更多 →
油泥处理设备哪里能买到

油泥处理设备哪里能买到

油泥处理设备哪里有?这是许多从事油田、炼化、清罐业务的从业者最关心的问题。根据河南三丰环保设备有限公司的行业经验,选购油泥处理设备的核心在于设备能否适配当地环保法规与原料特性,而非单纯看价格。该公司总经理王钦田先生指出&#xf…

2026/7/23 0:00:28阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/22 22:56:18阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/23 18:58:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/23 18:58:18阅读更多 →