← 中文资源

简体中文版本

面向前端的后端(BFF)

BFF 是按客户端类型(Web、移动、TV)各设一个服务端层:为该体验聚合并裁剪服务,把客户端需求与服务契约解耦。

阅读英文原文

概念定义

同一个 API 不可能同时对“蜂窝网络上的手机”和“光纤上的桌面”最优:载荷形状、延迟预算、缓存与刷新模式全都分歧。BFF 让每种体验对它的服务器自私起来。

工作机制

每个 BFF 组合下游服务、挑选字段、批量调用并在适合其客户端的边缘缓存。客户端只依赖自家 BFF 契约,服务团队从此不受客户端字段压力。BFF 归客户端团队所有——前端技能、后端运行时、每体验一条责任线。

使用场景

多客户端且需求可度量地不同、客户端团队想独立演进服务面、以及要求内部服务不承诺的稳定性的伙伴 API。

常见误区

BFF 不等于网关:网关做路由与协议翻译,BFF 含表现层逻辑与体验专属聚合。造一个万能 god-BFF 等于多加一跳重建通用 API。业务规则堆进 BFF,体验层就开始拥有本属于服务的决策——它是表现聚合器不是领域所有者;聚合逻辑在多个 BFF 稳定后应下沉为共享下游服务。

代码示例

export interface Endpoints {
  "GET /users/:id": { params: { id: string }; response: { id: string; name: string } };
  "POST /users": { body: { name: string }; response: { id: string } };
}

export function createClient(baseUrl: string) {
  async function call<
    K extends keyof Endpoints,
    E extends Endpoints[K],
  >(key: K, arg: E extends { body: infer B } ? B : E extends { params: infer P } ? P : never): Promise<E extends { response: infer R } ? R : never> {
    const [method, path] = (key as string).split(" ");
    const url = baseUrl + path.replace(/:id/, (arg as { id?: string }).id ?? "");
    const response = await fetch(url, {
      method,
      body: method === "GET" ? undefined : JSON.stringify(arg),
    });
    return (await response.json()) as never;
  }
  return { call };
}