最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
从零开发一个AI流式对话应用:SSE + BFF + Vite 实战指南
时间:2026-07-21 10:34:56 编辑:袖梨 来源:一聚教程网
写在前面
最近在做一个AI对话相关的项目,涉及到流式输出的场景。前端需要调用大模型API,但直接在前端调用会遇到两个问题:一是API Key暴露的安全风险,二是跨域问题。这篇文章就记录一下我是如何通过BFF层来解决这些问题的。

什么是BFF?
BFF(Backend For Frontend),直译过来就是“为前端服务的后端”。这个概念在微服务架构中很常见,但在大前端领域同样适用。
传统模式下,前端直接调用后端Java/Go服务提供的RESTful接口,实现数据的增删改查。但随着前端业务越来越复杂,特别是涉及到流式输出、二进制数据处理等场景时,直接让前端处理这些逻辑会让代码变得臃肿且难以维护。
于是我们可以在前端和后端之间加一层Node服务:
text
前端(Vue/React) → Node(BFF) → 后端(Java/LLM)
这一层Node服务可以帮我们做很多事情:
- 聚合多个接口的数据
- 处理流式输出的解析逻辑
- 隐藏敏感的API Key
- 解决跨域问题
SSE(Server-Sent Events)是什么?
SSE是一种基于HTTP的服务器推送技术,允许服务器向客户端推送事件流。与WebSocket不同,SSE是单向的,只能由服务器向客户端发送数据。
在AI对话场景中,大模型通常以流式方式返回结果,SSE正是处理这种场景的理想方案。
项目结构一览
text
stream-bff/├── src/│ ├── App.vue# 前端主组件│ └── main.js# Vue入口├── server.mjs # BFF后端服务(Express)├── vite.config.js # Vite配置(含袋里)├── .env.local # 环境变量(API Key)├── package.json # 项目依赖└── readme67.md# 笔记文档
环境配置
1. 安装依赖
bash
pnpm add express dotenv
2. 环境变量管理
在.env.local中存放敏感信息:
env
VITE_DEEPSEEK_API_KEY=your_api_key_here
注意:.env.local应该添加到.gitignore中,避免API Key泄露。
3. Vite袋里配置
跨域问题的本质是浏览器的同源策略:只要域名、端口、协议任意一个不同,就会触发跨域限制。
vite.config.js中配置袋里来解决跨域:
javascript
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'export default defineConfig({plugins: [vue()],server: {proxy: {'/api': {target: 'http://localhost:3000',secure: false,rewrite: (path) => path.replace(/^/api/, '')}}}})
这样,前端请求/api/stream会被Vite袋里转发到http://localhost:3000/stream,完美绕过了跨域问题。
BFF层实现
Express服务搭建
server.mjs是BFF层的核心:
javascript
import * as dotenv from 'dotenv';import express from 'express';dotenv.config({path: ['.env.local', '.env']});const app = express();const port = 3000;app.get('/', (req, res) => {res.send('hello world');});// 流式输出接口app.get('/stream', async (req, res) => {const { prompt } = req.query;const endpoint = 'https://api.deepseek.com/v1/chat/completions';try {const response = await fetch(endpoint, {method: 'POST',headers: {'Authorization': `Bearer ${process.env.VITE_DEEPSEEK_API_KEY}`,'Content-Type': 'application/json'},body: JSON.stringify({model: 'deepseek-v4-flash',stream: true,messages: [{ role: 'user', content: prompt }]})});// response.body 是 ReadableStream// 这里可以进行流式数据的处理和转发console.log(response.body);} catch (err) {console.log(err);}});app.listen(port, () => {console.log(`服务器在${port}端口启动了`);});
请求链路
text
前端:5173/api/stream → Vite袋里转发 → BFF:3000/stream → DeepSeek API
前端实现
App.vue中的核心逻辑:
vue
<script setup>import { ref } from 'vue';const question = ref('');const content = ref('');const stream = ref(true);const update = async () => {// 发送请求到BFF层fetch(`/api/stream?prompt=${question.value}`).then(res => res.json()).then(data => {console.log(data);});}</script><template><div class="container"><div><label>输入:</label><input class="input" v-model="question" /><button @click="update">提交</button></div><div class="output"><div><label>Streaming</label><input type="checkbox" v-model="stream" /></div><div>{{ content }}</div></div></div></template><style>.container {display: flex;flex-direction: column;align-items: start;justify-content: start;height: 100vh;font-size: 0.85rem;}.input {width: 200px;}.output {margin-top: 10px;min-height: 300px;width: 100%;text-align: left;}button {padding: 0 10px;margin-left: 6px;}</style>
启动服务
项目需要同时启动两个服务:
bash
# 终端1:启动Vite开发服务器(前端)npm run dev# 终端2:启动BFF服务(后端)node server.mjs
踩坑记录
关于502错误
配置袋里后如果遇到502,通常是因为:
- BFF服务没有启动(确认端口3000是否在监听)
- 袋里的目标地址配置错误
- 目标服务返回了非预期的响应
关于API Key安全
前端代码中的环境变量只有在构建时才会被替换,如果直接在前端调用大模型API,用户可以通过查看源代码获取到API Key。通过BFF层转发,API Key只存在于服务端,安全性大大提高。
总结
通过BFF层的引入,我们实现了:
- 解决跨域问题- Vite袋里将请求转发到同源的BFF服务
- 隐藏敏感信息- API Key存储在服务端,不会暴露给前端
- 简化前端逻辑- 复杂的流式数据处理交给BFF层处理
- 架构更清晰- 前端专注于UI交互,BFF层负责数据适配和转发
这种模式在微前端、大前端架构中非常实用,特别是当我们需要对接多个后端服务或第三方API时,BFF层的价值会更加明显。
相关文章
- 检疫区最后一站结膜炎与红眼区别一览 07-21
- 超大杯研究员的异常求汁欲第二章流程及单词出处 07-21
- 斗罗大陆诛邪传说什么时候上线 07-21
- 原神八重神子选精通沙还是攻击沙好 07-21
- 我不是盐神网站入口在哪 07-21
- 冒险者旅馆2全流程通关攻略是什么 07-21