logo
  • 指南
  • 配置
  • 插件
  • API
  • 示例
  • 社区
  • Modern.js 2.x 文档
  • 简体中文
    • 简体中文
    • English
    • 开始
      介绍
      快速上手
      版本升级
      名词解释
      技术栈
      核心概念
      页面入口
      构建工具
      Web 服务器
      基础功能
      路由
      路由基础
      配置式路由
      数据管理
      数据获取
      数据写入
      数据缓存
      渲染
      服务端渲染(SSR)
      服务端流式渲染(Streaming SSR)
      渲染缓存
      静态站点生成(SSG)
      渲染预处理 (Render Preprocessing)
      样式开发
      引入 CSS
      使用 CSS Modules
      使用 CSS-in-JS
      使用 Tailwind CSS
      HTML 模板
      引用静态资源
      引用 JSON 文件
      引用 SVG 资源
      引用 Wasm 资源
      调试
      数据模拟(Mock)
      网络代理
      使用 Rsdoctor
      使用 Storybook
      测试
      Playwright
      Vitest
      Jest
      Cypress
      路径别名
      环境变量
      构建产物目录
      部署应用
      进阶功能
      使用 Rspack
      使用 BFF
      基础用法
      运行时框架
      扩展 BFF Server
      扩展一体化调用 SDK
      文件上传
      跨项目调用
      优化页面性能
      代码分割
      静态资源内联
      产物体积优化
      React Compiler
      提升构建性能
      浏览器兼容性
      配置底层工具
      源码构建模式
      服务端监控
      Monitors
      日志事件
      指标事件
      国际化
      基础概念
      快速开始
      配置说明
      语言检测
      资源加载
      路由集成
      API 参考
      高级用法
      最佳实践
      自定义 Web Server
      专题详解
      模块联邦
      简介
      开始使用
      应用级别模块
      服务端渲染
      部署
      集成国际化能力
      常见问题
      依赖安装问题
      命令行问题
      构建相关问题
      热更新问题
      已下线功能
      📝 编辑此页面
      上一页扩展 BFF Server下一页文件上传

      #扩展一体化调用 SDK

      BFF 函数的一体化调用在 CSR 和 SSR 是同构的。Modern.js 封装的请求 SDK,在浏览器端依赖了 Fetch API,在服务端依赖了 node-fetch。但在实际业务场景下,有时需要对请求或响应做一些额外的处理,例如:

      • 在请求头中写入鉴权信息
      • 对响应的数据或错误进行统一的处理
      • 特定平台无法使用浏览器的原生 fetch 函数,需要使用其他方式发送请求

      针对上述的场景,Modern.js 提供了 configure 函数,开放了一系列扩展能力,可以用它配置 ssr 透传请求头,添加拦截器,自定义请求 SDK。

      注意

      configure 函数的调用需要在所有 BFF 请求发送前调用,以确保覆盖默认的请求配置。

      routes/page.tsx
      import { configure } from '@modern-js/plugin-bff/client';
      
      configure({
        // ...
      })
      
      const Index = () => <div>Hello world</div>
      export default Index;

      #配置 SSR 透传请求头

      在同时使用 Modern.js SSR 和 BFF 的场景下,常常需要将 SSR 页面请求上的一些请求头信息,透传给 BFF 服务。

      例如项目有页面地址是 https://website.com,该页面是 SSR 的,在组件中会调用 API 接口 https://website.com/api/info,该接口需要用户的 cookie 信息做鉴权。页面在请求该 API 接口时,需要将 SSR 页面请求的 cookie 传给 BFF。

      目前以下请求头在 Modernjs 中是自动透传的:

      ['cookie', 'user-agent', 'x-tt-logid', 'x-tt-stress']

      可以通过 configure 配置请求头。例如以下例子,Modern.js 会自动将 SSR 页面请求的 x-uid 信息透传给 BFF 服务:

      configure({
        allowedHeaders: ['x-uid']
      })

      #添加拦截器

      在有些业务场景下需要对请求和响应进行统一的处理,这种场景下可以通过配置拦截器满足需求:

      configure({
        // 这里的 request 是一体化默认的请求工具,interceptor 函数需返回一个新的 request。
        // 新 request 的出参必须是 parse body 之后的结果
        interceptor(request){
          return async(url, params) => {
            const res = await request(url, params);
            return res.json();
          };
        }
      });

      #自定义请求 SDK

      如果仅仅通过配置拦截器无法满足需求,希望自定义请求函数,也可以通过 configure 进行配置:

      import nodeFetch from 'node-fetch';
      
      const customFetch = (input: RequestInfo | URL, init: RequestInit) => {
        const curFetch = process.env.MODERN_TARGET !== 'node' ? fetch : nodeFetch as unknown as typeof fetch;
        return curFetch(input, init).then(async res => {
          const data = await res.json();
          data.hello = 'hello custom sdk';
          return data;
        });
      };
      
      configure({
        request: customFetch,
      });

      配置自定义请求函数有以下约定:

      • 函数的入参与浏览器中的 Fetch 或 node-fetch 对齐,所有 BFF 函数的一体化调用会通过该函数发送请求。
      • 函数出参必须是接口实际返回的数据,不能是 Promise,否则会导致 BFF 函数无法正常返回数据。
      • 如果是 SSR 项目,函数必须要同时支持浏览器端和服务器端发送请求。

      下面是使用 axios 定制自定义请求函数的示例:

      App.tsx
      import { configure } from '@modern-js/plugin-bff/client';
      import type { Method, AxiosRequestHeaders as Headers } from 'axios';
      
      configure({
        async request(...config: Parameters<typeof fetch>) {
          const [url, params] = config;
          const res = await axios({
            url: url as string,  // 这里因为 fetch 和 axios 类型有些不兼容,需要使用 as
            method: params?.method as Method,
            data: params?.body,
            headers: params?.headers as Headers,
          });
          return res.data;
        },
      });