前端直连LLM必踩2大致命坑!BFF中转流式SSE完整方案,一套代码解决密钥泄露+分片解析报错
前言做Vue AI对话页面90%新手会踩两个线上致命大坑前端直接请求DeepSeek接口API Key打包进前端抓包/查看源码直接泄露被盗刷高额账单纯前端手写SSE流式解析TCP网络分包截断JSON疯狂报parse错误、文字丢失、乱码很多教程只给前端极简demo完全不提安全风险也没有完整BFF中转层落地代码。本文带你搭建Vite Vue3 Express BFF后端完整流式对话架构读完你能学到BFF层是什么、为什么AI项目必须加中转层完整三层调用链路Vue前端 → Node BFF → DeepSeek大模型Express转发SSE流式响应标准写法处理二进制流透传优化版前端流式解析代码极简buffer容错逻辑Vite代理跨域配置解决前后端端口跨域问题全套可复制运行代码 高频踩坑清单直接上线使用一、先搞懂BFF中转层解决两大核心痛点1.1 安全痛点前端不能存放大模型API密钥Vite中VITE_开头环境变量会打包进前端产物任何人打开开发者工具、抓网络请求都能拿到完整Key存在被盗刷风险。BFF解决方案密钥只存在Node服务端.env前端永远看不到真实鉴权凭证。1.2 工程化痛点统一接口、降低前端复杂度没有BFF前端要处理二进制解码、分片缓存、异常捕获、接口切换逻辑代码臃肿拥有BFF统一封装LLM调用逻辑前端只需要请求本地/api/stream后续切换大模型、加限流、过滤敏感词只改后端前端零改动1.3 完整三层调用链路Vue页面(5173端口) → Vite代理转发 → Express BFF(3000端口) → DeepSeek官方API二、项目环境初始化2.1 安装依赖# Vue前端依赖npminstallvue# BFF后端依赖npminstallexpress dotenv2.2 环境变量区分前后端项目根目录.env.localBFF后端读取不会暴露前端DEEPSEEK_API_KEYsk-你的DeepSeek密钥前端无需存放任何LLM密钥彻底规避泄露风险2.3 vite.config.js 代理跨域配置关键import{defineConfig}fromviteimportvuefromvitejs/plugin-vueexportdefaultdefineConfig({plugins:[vue()],server:{proxy:{// 匹配前端/api开头请求转发到3000端口BFF服务/api:{target:http://127.0.0.1:3000,changeOrigin:true,rewrite:pathpath.replace(/^\/api/,)}}}})前端请求/api/streamVite自动转发为http://127.0.0.1:3000/stream消除跨域报错。三、完整BFF后端代码 server.jsExpress流式转发import*asdotenvfromdotenv;importexpressfromexpress;dotenv.config({path:[.env,.env.local]});constappexpress();constport3000;// 解析url参数app.use(express.urlencoded({extended:true}));// 基础测试路由app.get(/,(req,res){res.send(BFF服务运行正常访问 /api/stream 发起AI对话);});// SSE流式中转核心接口app.get(/stream,async(req,res){const{prompt}req.query;if(!prompt)returnres.status(400).send(prompt参数不能为空);constendpointhttps://api.deepseek.com/chat/completions;constapiKeyprocess.env.DEEPSEEK_API_KEY;constmodeldeepseek-v4-flash;// SSE标准响应头必须设置否则无法持续推送流res.setHeader(Content-Type,text/event-stream);res.setHeader(Cache-Control,no-cache);res.setHeader(Connection,keep-alive);res.flushHeaders();try{// 请求DeepSeek流式接口constllmResawaitfetch(endpoint,{method:POST,headers:{Authorization:Bearer${apiKey},Content-Type:application/json,},body:JSON.stringify({model,stream:true,messages:[{role:user,content:prompt}],}),});// 把大模型返回的二进制流直接透传给前端llmRes.body.pipe(res);// 客户端关闭连接时销毁请求避免资源占用req.on(close,(){llmRes.body.destroy();res.end();});}catch(error){console.error(LLM接口请求失败,error);res.write(data: {error:服务异常}\n\n);res.write(data: [DONE]\n\n);res.end();}});app.listen(port,(){console.log(BFF中转服务启动成功端口${port});});后端核心逻辑说明SSE响应头三件套告知浏览器保持长连接、禁用缓存持续接收数据流pipe(res)二进制流直接透传无需后端解析JSON性能更高密钥存放服务端环境变量前端完全无法获取监听客户端断开事件主动销毁流防止后台无效请求堆积四、Vue3前端完整代码 App.vue优化版流式解析script setup import { ref } from vue // 页面响应式状态 const question ref(讲一个中国龙的故事) const stream ref(true) // 是否开启打字机流式输出 const content ref() // 存储完整回答用于关闭流式时一次性渲染 let accumulatedText // 核心请求函数 async function update() { if (!question.value.trim()) return content.value accumulatedText // 请求本地BFF代理接口不会跨域、无密钥泄露 const url /api/stream?prompt${encodeURIComponent(question.value)} const response await fetch(url) const reader response.body.getReader() const decoder new TextDecoder(utf-8, { stream: true }) let buffer while (true) { const { done, value } await reader.read() if (done) break // 二进制转文本stream:true兼容跨分片中文 buffer decoder.decode(value, { stream: true }) // 按换行分割所有报文 const lines buffer.split(\n) // 最后一行大概率是不完整分片存入buffer下次拼接 buffer lines.pop() || // 逐行解析有效data报文 for (const line of lines) { if (!line.startsWith(data: )) continue const dataStr line.slice(6) // 流结束标识直接跳过 if (dataStr [DONE]) continue try { const json JSON.parse(dataStr) // 提取增量文字 const deltaText json.choices?.[0]?.delta?.content || accumulatedText deltaText // 流式开启则实时更新页面打字机效果 if (stream.value) { content.value accumulatedText } } catch (err) { // JSON解析失败直接忽略残缺片段已存入buffer continue } } } // 关闭流式全部接收完成后一次性渲染全文 if (!stream.value) { content.value accumulatedText } } /script template div classcontainer !-- 提问输入区 -- div label输入提问/label input classinput v-modelquestion placeholder输入你的问题 / button clickupdate提交AI问答/button /div !-- 流式开关 AI回答展示 -- div classoutput div stylemargin-bottom:8px; label开启Streaming流式打字机/label input typecheckbox v-modelstream / /div div stylewhite-space: pre-wrap;{{ content }}/div /div /div /template style scoped .container { display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; height: 100vh; font-size: 0.85rem; padding: 20px; } .input { width: 300px; padding: 4px 8px; } .output { margin-top: 12px; min-height: 300px; width: 100%; text-align: left; line-height: 1.7; } button { padding: 4px 12px; margin-left: 8px; cursor: pointer; } /style前端流式优化点对比纯前端直连方案请求地址统一代理只访问本地/api/stream不暴露第三方LLM接口极简buffer容错分割后把最后一行残缺报文放回buffer逻辑更简洁稳定TextDecoder({stream:true})解决跨分片中文乱码问题分离accumulatedText完整缓存支持一键切换流式/一次性渲染增加输入空值拦截避免无效请求五、完整运行步骤新建.env.local填入DeepSeek密钥终端启动BFF后端服务nodeserver.js新开终端启动Vite前端npmrun dev打开页面输入提问勾选/取消Streaming测试两种输出模式六、开发高频踩坑清单必看坑1前端直接请求LLM接口密钥泄露被盗刷现象上线后账单暴涨开发者工具Network面板可见完整Authorization密钥解决方案全部请求走BFF中转密钥仅存Node服务端环境变量坑2BFF未设置SSE响应头流式一次性返回现象页面等待全部生成后才展示文字无逐字打字效果修复必须添加text/event-stream、no-cache、keep-alive三个响应头坑3Vite代理502跨域报错原因BFF后端未启动、端口不匹配、代理rewrite路径错误检查确认BFF运行在3000端口vite代理配置正确坑4TCP分包截断JSON控制台频繁parse报错根源网络分片把一条data: JSON拆成两段解决代码中buffer缓存末尾残缺行下一轮循环拼接完整再解析坑5中文跨分片出现乱码问号修复new TextDecoder(utf-8, { stream: true })开启流式解码坑6切换流式开关文字错乱、重复叠加优化每次请求重置accumulatedText完整缓存分开实时渲染与最终渲染逻辑七、两种架构方案对比方案前端直连LLMBFF中转架构本文方案密钥安全极低极易泄露极高密钥仅存服务端接口维护切换模型需修改全部前端代码仅修改后端前端无感知前端复杂度高需处理鉴权、流、异常低仅处理本地流式解析扩展能力无法加限流、敏感词过滤后端统一加权限、限流、校验线上风险盗刷、接口暴露安全可控生产推荐八、项目扩展优化方向增加请求限流后端引入express-rate-limit防止恶意刷接口POST传参替代URL拼接避免长prompt参数超长改用body传递提问中断生成搭配AbortController实现停止AI输出功能多轮对话扩展BFF接口接收完整messages数组支持连续聊天异常统一处理后端捕获401/429/500错误标准化错误报文返回前端Markdown渲染流接收完成后使用marked解析富文本格式九、总结生产环境绝对禁止前端直连大模型APIBFF中转层是安全底线杜绝密钥泄露盗刷SSE流式输出核心依靠二进制长连接buffer缓存是解决TCP分片截断的必备容错逻辑Vite代理转发解决前后端跨域Express通过pipe透传LLM二进制流性能最优整套架构分层清晰前端负责页面交互、BFF负责安全中转、大模型负责文本生成可直接落地商用AI对话产品。

相关新闻

Gamma怎样用结构提示生成演示框架_Gamma用结构提示生成演示框架【结构提示】

Gamma怎样用结构提示生成演示框架_Gamma用结构提示生成演示框架【结构提示】

利用结构化提示能迅速弄出清晰的演示框架, 其一, 借助预定义模板输入涵盖引言、背景、核心技术等内容方向的提示, 其二, 运用分段式模块逐个生成引言、技术说明、案例与挑战分析再进行整合, 其三, 凭借“问题 - 原因 - 解决方案”等关键词触发内置结构模式来提升效率。具备AI智…

2026/8/5 23:56:05 阅读更多 →
基于pytest的企业级多租户自动化测试实践

基于pytest的企业级多租户自动化测试实践

1. 企业级多租户测试体系概述 在当今SaaS服务盛行的时代,多租户架构已成为企业级应用的标配。这种架构允许单个应用实例服务多个客户(租户),每个租户的数据和配置相互隔离。作为质量保障的关键环节,自动化测试体系必须…

2026/8/5 23:56:05 阅读更多 →
【C语言零基础】通关01: 初识C语言

【C语言零基础】通关01: 初识C语言

目录1. 初识C语言2. C语言的历史和辉煌2.1 历史2.2 C语言的活跃度3. 学习C语言需要什么工具?3.1 翻译工具:编译器链接器3.2 编译器的对比4.第一个C语言程序4.1 VS项目,源文件,头文件介绍4.2 第一个C语言函数4.3 main函数&#xff…

2026/8/5 23:56:04 阅读更多 →

最新新闻

JMeter教程|0到1学会接口性能压测第12课-JMeter并发测试

JMeter教程|0到1学会接口性能压测第12课-JMeter并发测试

JMeter是一款开源免费的接口性能压测工具,在企业中用的较为广泛,上节我们学习了JMeter常用监听器。今天分享JMeter并发测试,后续文章都会系统分享干货,带大家从0到1学会JMeter,另外还有教程等同步资料,文末…

2026/8/6 0:54:24 阅读更多 →
ncmdump终极指南:专业解密网易云音乐NCM格式的完整方案

ncmdump终极指南:专业解密网易云音乐NCM格式的完整方案

ncmdump终极指南:专业解密网易云音乐NCM格式的完整方案 【免费下载链接】ncmdump ncmdump - 网易云音乐NCM转换 项目地址: https://gitcode.com/gh_mirrors/ncmdu/ncmdump 在数字音乐版权保护日益严格的今天,网易云音乐NCM格式转换成为众多音乐爱…

2026/8/6 0:54:24 阅读更多 →
AI写产品评测到底靠不靠谱?揭秘92%的评测文章被算法识别的3个致命破绽

AI写产品评测到底靠不靠谱?揭秘92%的评测文章被算法识别的3个致命破绽

更多请点击: https://codechina.net 第一章:AI写产品评测到底靠不靠谱?揭秘92%的评测文章被算法识别的3个致命破绽 当AI生成的评测文章在搜索引擎中批量涌现,平台反作弊系统正以前所未有的精度将其标记为“低信度内容”。第三方实…

2026/8/6 0:54:24 阅读更多 →
AI学日语到底靠不靠谱?实测12款工具+378小时数据对比,这3个模型真正改变学习轨迹

AI学日语到底靠不靠谱?实测12款工具+378小时数据对比,这3个模型真正改变学习轨迹

更多请点击: https://kaifayun.com 第一章:AI学日语到底靠不靠谱?实测12款工具378小时数据对比,这3个模型真正改变学习轨迹 过去三个月,我们对12款主流AI日语学习工具(含ChatGPT-4o、Claude 3.5 Sonnet、G…

2026/8/6 0:54:24 阅读更多 →
政务外网环境下视频监控资源整合:新增仓库接入实施方案

政务外网环境下视频监控资源整合:新增仓库接入实施方案

一、现状本项目处于政务外网严格的网络边界环境内。原仓库视频监控系统已稳定运行,包含13路存量监控点位,覆盖主要出入口及核心库区。二、需求接入策略与技术路线: 针对本次新建的12路监控摄像头,将严格遵循政务外网接入规范&…

2026/8/6 0:53:24 阅读更多 →
excel怎么转txt?盘点2026年7款PDF格式转换工具,覆盖单转与批量导出

excel怎么转txt?盘点2026年7款PDF格式转换工具,覆盖单转与批量导出

上个月给公司投标,好不容易把技术方案定稿,甲方突然说还得附一份单独的材料清单,格式必须是纯文本TXT。我手里只有一份完整的方案PDF,打开看着满屏的表格和条款,心里直犯嘀咕:难道要手动敲一遍?…

2026/8/6 0:52:23 阅读更多 →

日新闻

深入解析LimboAI C++内核:架构设计与性能优化实战

深入解析LimboAI C++内核:架构设计与性能优化实战

1. 项目概述:为什么我们需要深入LimboAI的C内核?如果你是一名使用Godot引擎的游戏开发者,尤其是对AI行为逻辑有较高要求的项目,那么LimboAI这个名字你大概率不会陌生。它作为Godot 4生态中一个备受瞩目的行为树与状态机插件&#…

2026/8/6 0:00:06 阅读更多 →
Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

1. 项目概述与核心思路大家好,我是老张,一个在游戏开发一线摸爬滚打了十多年的老码农。今天咱们接着聊《空洞骑士》风格2D动作游戏的Demo制作。上一期我们搭好了基础框架,处理了角色移动和碰撞,这一期,我们要让游戏世界…

2026/8/6 0:00:06 阅读更多 →
被动防火门市场前景发展趋势

被动防火门市场前景发展趋势

被动防火门依靠材质结构、密闭构造阻隔烟火蔓延,无需电控启动,是建筑被动消防系统核心构件,行业依托新规管控、城市更新、工业安全升级迎来稳定扩容,整体朝着合规化、专项化、低碳化、智能化方向发展。现阶段 GB12955‑2024 新版国…

2026/8/6 0:00:06 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/5 23:28:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/5 21:00:14 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/5 23:46:51 阅读更多 →