🎉 AI 项目里为什么需要 BFF?因为我实在不想在前端处理二进制流

写在前面:今天老师讲了一个我深有感触的概念------BFF(Backend For Frontend,为前端服务的后端)。上节课我们学流式输出,前端直接调 DeepSeek 的 API,结果要处理 ReadableStream、TextDecoder、while 循环......代码又臭又长。老师说:"这些脏活累活,交给 BFF 层干啊!" 前端只负责展示,后端代理转发的逻辑丢给 Node.js 的 BFF 层。听完我大喊:这才是工程化!


一、BFF 是什么?为前端"打工"的后端

1.1 为什么需要 BFF?

老师说:

"前端(Vue/React)→ Node(BFF)→ 后端(Java)。"

传统三层架构:

复制代码
前端(Vue/React) → 后端(Java/Go)→ 数据库

加上 BFF 的四层架构:

复制代码
前端(Vue/React) → BFF(Node.js) → 后端(Java/Go) → 数据库

BFF 就是"为前端服务的后端"。 它不是替代真正的后端,而是在前端和后端之间加了一层"翻译官"。

1.2 BFF 适合做什么?

适合 BFF 做的事 不适合 BFF 做的事
代理 LLM 请求(隐藏 API Key) 连接数据库、CRUD
处理流式输出的二进制流 复杂的业务逻辑
格式化数据、适配前端需求 高安全性、高并发的核心业务
轻量级转发、聚合多个接口 事务管理、分布式处理

老师说:

"大前端工程师自己写常见的 Node 服务,来达成自身的需求。"

BFF 是"大前端"的护城河------前端工程师自己就能搞定的后端活儿。


二、BFF 实战:Express 搭建代理服务器

2.1 初始化服务器

server.mjs

javascript 复制代码
import * as dotenv from 'dotenv';
import express from 'express';

dotenv.config({
    path: ['.env.local', '.env'],
});

const app = express();
const port = 3000;

app.listen(port, () => {
    console.log(`Server is running on port ${port}`);
});

老师用的是 Express------Node.js 最常用且最简单的开发框架。

2.2 普通的 GET 路由

javascript 复制代码
app.get('/', (req, res) => {
    res.send('Hello World!');  // 一次性发送
});

2.3 流式输出的代理路由

javascript 复制代码
app.get('/stream', async (req, res) => {
    const { prompt } = req.query;

    const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${process.env.VITE_DEEPSEEK_API_KEY}`,
        },
        body: JSON.stringify({
            model: 'deepseek-v4-flash',
            stream: true,
            messages: [{ role: 'user', content: prompt }]
        })
    });

    console.log(response.body); // ReadableStream
});

BFF 在这里做了一件非常重要的事:

前端不需要知道 API Key 了。API Key 放在 BFF 层,前端只发请求到 BFF,BFF 带上 Key 去调 LLM。

这就是 安全性的提升------API Key 不会暴露在前端代码里。

2.4 完整的数据流

bash 复制代码
前端(5173):fetch('/api/stream?prompt=...')
  ↓
Vite 代理:vite.config.js 中 proxy 配置
  ↓
BFF(3000):/api → /stream 路由 → 转发到 DeepSeek API
  ↓
DeepSeek API:流式返回数据
  ↓
BFF 处理流数据 → 返回给前端
  ↓
前端展示

老师说:

"前端 fetch → Node(BFF)→ LLM 服务器。前端业务非常复杂,二进制流对象,解码,解析 data------各种情况。抽象一下,放到大前端 BFF 层,Node 里面,前端简洁,降低难度。"


三、跨域问题:Vite Proxy 来解决

3.1 什么是跨域?

老师说:

"只要域名、端口、协议(http/https)不同,fetch 等请求的时候,跨域,同源策略。"

前端运行在 http://localhost:5173,BFF 运行在 http://localhost:3000

端口不同,浏览器就会拦截跨域请求。

3.2 Vite 的 Proxy 方案

vite.config.js

javascript 复制代码
// vite 工程,proxy 配置,代理一下请求,并转发出去
export default defineConfig({
    plugins: [vue()],
    server: {
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                changeOrigin: true,
            }
        }
    }
});

老师说:

"/api 标志请求后端 API 接口。不跨域了,但是 502------因为前端不会提供这个路由。Vite 拦截所有 /api 开头的请求,代理转发到 :3000。"

前端的请求路径:

bash 复制代码
前端请求:/api/stream(不跨域了,因为是同源)
  ↓ Vite 识别到 /api 开头
  ↓ 自动转发
BFF 实际接收:/stream(去掉了 /api 前缀)

Vite Proxy 就像一个"快递中转站"------你把包裹交给同一个小区的快递站(5173),它帮你转发到另一个小区的站点(3000)。


四、BFF + 流式输出,前端代码变得多简单?

4.1 有 BFF 之前

前端要直接处理:

javascript 复制代码
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
    headers: { 'Authorization': `Bearer ${apiKey}` },
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
// ...while 循环读流......

4.2 有 BFF 之后

前端只需要:

javascript 复制代码
fetch('/api/stream')
    .then(res => res.json())
    .then(data => {
        console.log(data);
    });

当然,如果是流式输出,前端还是要处理流。但至少 API Key 不用暴露了,请求地址更短了,后端转发逻辑可以集中管理了。


五、总结:BFF 是大前端的"保护层"

概念 说明
BFF Backend For Frontend,为前端服务的后端
Express Node.js 最常用的 Web 开发框架
dotenv 读取 .env 文件的环境变量
跨域 不同端口/域名/协议的请求被浏览器拦截
Vite Proxy 代理转发前端请求到 BFF 后端
API Key 保护 Key 放在 BFF 层,前端不知道

BFF 的核心价值三句话:

  • 隐藏敏感信息(API Key)。
  • 降低前端复杂度(流式处理丢给 BFF)。
  • 解耦前后端(前端不直接调第三方 API)。

写在最后

今天最大的收获,是理解了 BFF 在 AI 项目中的角色。以前觉得前端直接调 API 就行了,现在知道了------流式输出的二进制流处理太复杂了,API Key 放在前端也太危险了。BFF 就是用来"挡在前面前面"的------脏活累活它干,安全问题它扛。

下次面试官问你:"BFF 层在 AI 项目中有什么作用?"

你可以淡定地说:

"BFF(Backend For Frontend)在前端和后端之间加了一层中继。在 AI 项目中有三个核心作用:① 隐藏 API Key ------前端发请求到 BFF,BFF 带上 Key 去调 LLM,Key 不暴露在浏览器端;② 降低前端复杂度 ------流式输出的 ReadableStream 处理、数据解析在 BFF 层完成,前端只负责展示;③ 跨域代理 ------通过 Vite Proxy 将 /api 请求转发到 BFF 的对应端口,避免前端跨域问题。实现上可以用 Express 快速搭建 BFF 服务,一行 proxy 配置解决转发问题。"

然后看着面试官满意的表情,心里默念:这波,又稳了。


本文所有代码示例均来自课堂学习资料,真实可运行。

相关推荐
Revolution611 小时前
改一个订单筛选,为什么要在六个目录里来回找,前端项目目录到底要怎么拆
前端·前端工程化
阳光是sunny1 小时前
LangGraph高级教程:Multi Schema多状态管理详解
前端·人工智能·后端
mCell2 小时前
从 TodoList 到 Microsoft To Do:全栈工程师到底要管什么?
前端·编程语言·全栈
阳光是sunny2 小时前
LangGraph实战教程:状态管理与`graph.invoke`入参深度解析
前端·人工智能·后端
神奇小汤圆3 小时前
深入解析 Flink Kafka Connector:原理、配置与最佳实践
前端·后端
科技之门3 小时前
百公里管网漏损分级定位实战方案2026
前端·人工智能·算法
xyphf_和派孔明3 小时前
企业级微前端项目完整创建步骤,第三步:配置 Vue 子应用
前端·javascript
自强的小白3 小时前
条件查询或查询全部时时前端请求数据等时间格式
前端
阳光是sunny3 小时前
LangGraph实战教程:一文搞懂图的状态(State)管理
前端·人工智能·后端