同构API请求实战:react-isomorphic-starterkit如何用一层fetch-plus打通Node与浏览器
【免费下载链接】react-isomorphic-starterkitCreate an isomorphic React app in less than 5 minutes项目地址: https://gitcode.com/gh_mirrors/re/react-isomorphic-starterkit
react-isomorphic-starterkit 是一个 5 分钟内就能搭起同构 React 应用的开源脚手架:Koa 负责服务端渲染,Webpack 双端构建,React Transmit 负责数据预取与客户端水合。本文聚焦它最值得抄作业的一环——如何用 fetch-plus 搭建同构 API 请求层,让同一份请求代码在 Node 和浏览器中都能直接跑通,并顺带解决跨域难题。
同构 API 请求为什么难?
做服务端渲染(SSR)时,请求代码往往要在两个"性格迥异"的环境里执行:
| 环境 | 特点 | 直接请求外网 API 会怎样 |
|---|---|---|
| Node 服务端 | 没有window,不受 CORS 限制 | 可以直连,但浏览器端没这种自由 |
| 浏览器客户端 | 受同源策略约束 | 外网 API 没有 CORS 头就会被拦截 |
很多模板的做法是服务端、客户端各写一套请求逻辑,结果数据不一致、维护成本翻倍。react-isomorphic-starterkit 的思路很干脆:请求层只写一次,通过"端点(endpoint)"抽象自动适配环境。
fetch-plus:把 API 封装成一个可复用的端点
整个方案的灵魂只有 20 行,全部在 src/apis/github.js 里:
const endpoint = fetchPlus.connectEndpoint(githubServerUrl()); endpoint.addMiddleware(plusJson()); module.exports = endpoint;它做对了三件小事:
connectEndpoint:把一个 base URL 变成"端点"。之后调用githubApi.browse(["repos", "xxx", "stargazers"], { query: { page } })这样的路径数组 + 查询参数即可,fetch-plus 会自动拼出完整 URL 并序列化 query,不用手拼字符串。addMiddleware(plusJson()):中间件自动把响应体解析成 JSON,业务代码里.then(json => ...)直接拿数据,省掉到处response.json()。- fetch 实现统一:package.json 中同时依赖
cross-fetch、fetch-plus、fetch-plus-json、fetch-plus-bearerauth——前者保证浏览器端有稳定的 fetch 实现,后两者分别是 JSON 中间件和 Bearer 鉴权中间件,按需挂载。
一行环境开关:SERVER与CLIENT切换请求地址
githubServerUrl() 是环境适配的关键:
- 服务端(
__SERVER__):直连https://api.github.com; - 客户端(
__CLIENT__):返回当前站点的同源路径/api/github,而不是外网地址。
而__SERVER__/__CLIENT__并不是运行时的判断,而是由 Webpack 的DefinePlugin在打包时注入的常量,见 configs/webpack.client.js 与 configs/webpack.server.js。这意味着:
- 客户端产物里服务端分支会被死代码消除,体积更小;
- 同一份 src/apis/github.js 无需任何条件判断就能被双端共享,这就是"一层 fetch-plus 打通两端"的含义。
服务端反代:浏览器走同源,服务器转外网
浏览器请求的是同源路径/api/github/...,那它最终怎么到 GitHub?答案在 src/server.js 里的一段 Koa 代理配置:
app.use(koaProxy({ host: githubApi.url, // 端点的 base URL match: /^\/api\/github\//i, map: (path) => path.replace(/^\/api\/github\//i, "/") }));完整数据流是这样的:
浏览器 →
http://localhost:8000/api/github/repos/...(同源) → KoakoaProxy剥掉前缀 → 转发到https://api.github.com/repos/...→ 原路返回 JSON
这个设计一举三得:浏览器端彻底绕开 CORS;API 的真实地址集中收敛在服务端;将来换 API 提供方或加鉴权,只改端点一处即可。
业务层只关心数据:Transmit 预取 + 客户端续传
请求层搭好之后,业务代码可以干净到什么程度?看 src/containers/Main.js 中的取数函数——它被服务端渲染和客户端续传同时复用:
- 服务端:
Transmit.createContainer的 fragments 在renderToString阶段预取第一页 stargazers,数据随 HTML 一起输出; - 客户端:src/client.js 用
Transmit.render水合,之后滚动加载更多页时,走的是同一个fetchStargazers,只不过此时它请求的是同源代理路径。
也就是说,从 SSR 首屏到客户端增量加载,请求链路始终是"fetch-plus 端点 → 同环境地址 → (客户端时)Koa 反代",前后端零重复代码。
快速上手步骤:5 分钟跑起来
git clone https://gitcode.com/gh_mirrors/re/react-isomorphic-starterkit.git cd react-isomorphic-starterkit npm install npm run watch一条npm run watch同时启动服务端与客户端的 HMR 热更新,详见 README.md。生产部署则执行npm run build && npm start。
举一反三:把它改成你自己的 API 层
这套模式可以原样搬进你的项目,改造点只有三处:
- 复制 src/apis/github.js 的结构,把 base URL 换成自己的接口地址(服务端直连、客户端走同源前缀);
- 在 src/server.js 里照抄一段
koaProxy,代理你的 API 前缀; - 需要鉴权时,给端点追加 fetch-plus-bearerauth 中间件,统一注入 Token。
核心路径速查:
- API 请求层:src/apis/
- 服务端入口与代理:src/server.js
- 客户端水合入口:src/client.js
- 双端构建配置:configs/webpack.client.js、configs/webpack.server.js
小结:react-isomorphic-starterkit 用"fetch-plus 端点 + 构建期环境开关 + Koa 同源反代"三板斧,把同构应用中最容易写歪的 API 请求收敛成一层薄薄的封装。对新手而言,这 20 行 github.js 就是一份可直接照抄的同构请求层范本。
【免费下载链接】react-isomorphic-starterkitCreate an isomorphic React app in less than 5 minutes项目地址: https://gitcode.com/gh_mirrors/re/react-isomorphic-starterkit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考