cross-fetch、isomorphic-fetch 和 node-fetch 都是为了解决 JavaScript 在不同运行时(Node.js 与浏览器)中 fetch API 不一致的问题。node-fetch 专为 Node.js 环境设计,提供了轻量级的 HTTP 请求能力;isomorphic-fetch 和 cross-fetch 则是 polyfill 方案,旨在让同一套代码能在服务端和客户端无缝运行。随着 Node.js 18+ 原生支持 fetch,以及模块系统(ESM vs CJS)的演变,这三个包在架构选型中的定位发生了显著变化。
在构建全栈 JavaScript 应用时,HTTP 请求是不可或缺的一环。虽然浏览器原生支持 fetch API,但 Node.js 环境(尤其是 18 版本之前)长期缺乏标准实现。cross-fetch、isomorphic-fetch 和 node-fetch 都曾是为了解决这一鸿沟而诞生的方案,但它们的设计目标和适用场景截然不同。让我们从架构师的角度,深入对比它们在环境兼容性、模块系统和支持周期上的差异。
node-fetch 是专为 Node.js 环境设计的轻量级实现。
// node-fetch: 仅服务端使用
import fetch from 'node-fetch'; // v3 ESM
// const fetch = require('node-fetch'); // v2 CJS
const res = await fetch('https://api.example.com/data');
isomorphic-fetch 旨在抹平环境差异,自动检测运行时。
node-fetch,在浏览器中引入原生 fetch。// isomorphic-fetch: 全局注入
import 'isomorphic-fetch';
// 之后即可直接使用全局 fetch
const res = await fetch('https://api.example.com/data');
cross-fetch 同样追求通用性,但提供了更灵活的导入方式。
// cross-fetch: 显式导入
import fetch from 'cross-fetch';
const res = await fetch('https://api.example.com/data');
这是当前选型中最容易踩坑的地方,尤其是 node-fetch 的版本迭代。
node-fetch 在 v3 版本做出了破坏性更新。
import),不能在 CommonJS(require)中直接使用。// node-fetch v3: 必须使用 ESM
import fetch from 'node-fetch';
// node-fetch v2: 支持 CommonJS
const fetch = require('node-fetch');
isomorphic-fetch 主要基于 node-fetch v2 构建。
// isomorphic-fetch: 传统方式
import 'isomorphic-fetch'; // 副作用导入
cross-fetch 对模块系统的支持最为平滑。
// cross-fetch: 兼容两种模式
import fetch from 'cross-fetch'; // ESM
// const fetch = require('cross-fetch'); // CJS
随着 Node.js 18 正式发布,全局 fetch 已成为标准,这改变了选型逻辑。
isomorphic-fetch 目前已处于非活跃维护状态。
// ⚠️ 不推荐:isomorphic-fetch
// 维护频率低,依赖陈旧
import 'isomorphic-fetch';
node-fetch 仍在维护,但定位发生变化。
fetch。// ✅ 推荐:Node 18+ 原生 fetch
const res = await fetch('https://api.example.com/data');
// ⚠️ 仅旧版 Node 需要:node-fetch
import fetch from 'node-fetch';
cross-fetch 保持活跃维护,定位清晰。
// ✅ 推荐:跨平台库开发
import fetch from 'cross-fetch';
// 确保你的库在任何环境下都能工作
尽管存在差异,这三个包在核心 API 上保持高度一致,都遵循 WHATWG Fetch 标准。
GET, POST, PUT, DELETE 等标准动词。// 所有包都支持的标准用法
const response = await fetch('/api', {
method: 'POST',
body: JSON.stringify({ data: 123 })
});
const json = await response.json();
AbortController 取消请求。// 所有包都支持的取消请求
const controller = new AbortController();
const signal = controller.signal;
fetch('/api', { signal });
// 稍后调用 controller.abort() 取消
// 所有包都支持的 Header 设置
fetch('/api', {
headers: {
'Authorization': 'Bearer token',
'Content-Type': 'application/json'
}
});
| 特性 | node-fetch | isomorphic-fetch | cross-fetch |
|---|---|---|---|
| 主要环境 | Node.js 专用 | Node + 浏览器 (Polyfill) | Node + 浏览器 + React Native |
| 模块系统 | v3 仅 ESM, v2 仅 CJS | 主要 CJS | ESM + CJS 双支持 |
| 维护状态 | 活跃 (但建议用原生) | ❌ 非活跃/遗留 | ✅ 活跃维护 |
| 全局污染 | 否 (需导入) | 是 (副作用导入) | 否 (可显式导入) |
| Node 18+ | 建议用原生 fetch | 不建议使用 | 可作为 Polyfill 备用 |
node-fetch 适合纯 Node.js 后端服务,但请务必检查你的 Node 版本。如果是 Node 18 或更高,请直接使用全局 fetch,无需安装任何包。如果是旧版 Node 且无法升级,v2 版本是稳定选择,v3 版本仅适用于 ESM 项目。
cross-fetch 是构建通用 npm 库的首选。如果你正在开发一个需要同时运行在服务端渲染(SSR)、客户端静态站点(SSG)甚至 React Native 中的库,它能最大程度减少环境适配代码。
isomorphic-fetch 应被视为遗留技术。除非你正在维护一个深度依赖它的旧项目,否则不要在新代码中引入。它的维护停滞意味着未来的安全风险和兼容性问题。
最终思考:JavaScript 运行时正在趋同。随着 Node.js 原生支持 fetch,polyfill 的需求正在减少。未来的架构趋势是:优先使用原生 API,仅在必须兼容旧环境时使用 cross-fetch 作为降级方案。
仅建议在维护旧有遗留代码时使用 isomorphic-fetch,新项目应避免引入。该包目前已处于非活跃维护状态,内部依赖较旧的 node-fetch 版本,在现代 ESM 项目或 Node.js 18+ 环境中可能会遇到兼容性问题或冗余 polyfill。
如果你的项目需要构建通用库(Universal Library),或者需要在 Node.js、浏览器和 React Native 之间共享代码,请选择 cross-fetch。它 actively 维护,能自动处理不同环境的差异,且同时支持 ESM 和 CommonJS 模块系统,减少了配置负担。
如果你的代码仅运行在 Node.js 服务端,且版本低于 18(无原生 fetch),请选择 node-fetch。注意 v3 版本仅支持 ESM,若项目使用 CommonJS 则需锁定 v2 版本;若已是 Node.js 18+,则建议直接使用原生全局 fetch 而非此包。
Fetch for node and Browserify. Built on top of GitHub's WHATWG Fetch polyfill.
fetch as a global so that its API is consistent between client and server.For ease-of-maintenance and backward-compatibility reasons, this library will always be a polyfill. As a "safe" alternative, which does not modify the global, consider fetch-ponyfill.
The Fetch API is currently not implemented consistently across browsers. This module will enable you to use fetch in your Node code in a cross-browser compliant fashion. The Fetch API is part of the Web platform API defined by the standards bodies WHATWG and W3C.
npm install --save isomorphic-fetch
bower install --save isomorphic-fetch
require('isomorphic-fetch');
fetch('//offline-news-api.herokuapp.com/stories')
.then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
})
.then(function(stories) {
console.log(stories);
});
All open source code released by FT Labs is licenced under the MIT licence. Based on the fine work by jxck.