node-fetch 完整指南:在 Node.js 中引入标准 Fetch API
node-fetch 完整指南:在 Node.js 中引入标准 Fetch API
node-fetch 是一个轻量级模块,把浏览器原生的 window.fetch API 移植到 Node.js 运行时,让你可以用同构的 Promise 语法发起 HTTP(S) 请求、流式读写请求与响应体、自动解码 gzip/deflate/brotli 压缩内容,并借助 AbortSignal 取消请求。本文以仓库 README 为主体,结合源码实现与测试用例,系统讲解从安装配置、日常请求到高级流式用法与完整 API 的实战方案,读完即可在 Node.js 项目中可靠地落地 fetch 开发。
设计动机与定位
为什么不用 XMLHttpRequest 兼容层
社区早期通过把浏览器的 XMLHttpRequest 移植到 Node.js 来实现 fetch polyfill,而 node-fetch 选择了一条更直接的路线:从 Node.js 原生 http 模块直接构建出兼容 window.fetch 的 API,跳过 XHR 这层"中间人",因此代码量最小、语义最贴近 Fetch 标准。需要 isomorphic(同构)用法的场景,可以搭配 isomorphic-unfetch(服务端导出 node-fetch、客户端导出 whatwg-fetch)或 cross-fetch 使用。
核心特性
按 README 的 Features 一节,node-fetch 具备以下关键能力:
- 与
window.fetchAPI 保持一致,尽量贴合 WHATWG Fetch 规范与 Stream 规范,同时对已知差异做显式取舍并在文档中说明; - 原生 Promise 与 async/await 支持,无回调嵌套;
- 请求与响应体均使用 Node.js 原生 Readable 流;
- 正确解码 gzip/deflate/brotli 内容编码,并将
res.text()、res.json()等字符串输出自动转为 UTF-8; - 提供重定向次数限制、响应体大小限制、显式错误类型(docs/ERROR-HANDLING.md)等实用的扩展能力。
从 package.json 可以看到,当前仓库版本为 3.1.1,包入口为 src/index.js,类型定义随包发布在 @types/index.d.ts,依赖仅 data-uri-to-buffer、fetch-blob、formdata-polyfill 三个轻量库。
与客户端 fetch 的已知差异
node-fetch 刻意维护了一份与浏览器 window.fetch 的差异清单,用于在规范实现与 Node.js 现实之间做取舍:
- 3.x 版本的差异见 docs/v3-LIMITS.md;
- 2.x 版本的差异见 docs/v2-LIMITS.md。
如果你发现某个 window.fetch 提供的能力在 node-fetch 中缺失,可以在项目仓库提交 issue,也欢迎直接提交 Pull Request。
安装与模块加载
环境要求与安装
当前稳定版(3.x)要求 Node.js 12.20.0 及以上。更精确的引擎约束记录在 package.json 的 engines 字段:^12.20.0 || ^14.13.1 || >=16.0.0。
npm install node-fetch
ES Modules(ESM)
v3 起 node-fetch 是 ESM-only 模块(package.json 中 "type": "module"),标准导入方式:
import fetch from 'node-fetch';
CommonJS
v3 无法用 require() 直接导入。如果你暂时无法切换到 ESM,有两个选择:
- 使用 v2:v2 保持 CommonJS 兼容,且关键 bug 修复仍会持续发布到 v2 线:
npm install node-fetch@2
- 从 CommonJS 异步加载 v3:利用动态
import()包装一个兼容函数:
// mod.cjs
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
注入全局对象
不想在每个文件里显式导入,可以写一个 polyfill 模块把 fetch 及其相关类挂到 globalThis:
// fetch-polyfill.js
import fetch, {
Blob,
blobFrom,
blobFromSync,
File,
fileFrom,
fileFromSync,
FormData,
Headers,
Request,
Response,
} from 'node-fetch'
if (!globalThis.fetch) {
globalThis.fetch = fetch
globalThis.Headers = Headers
globalThis.Request = Request
globalThis.Response = Response
}
// index.js
import './fetch-polyfill'
// ...
注意这里通过 if (!globalThis.fetch) 做存在性保护,避免覆盖 Node.js 新版本自带的原生 fetch。从源码看,这些导出在 src/index.js 中统一 re-export。
版本升级
- 从 2.x 升级到 3.x,见 docs/v3-UPGRADE-GUIDE.md;
- 从 1.x 升级到 2.x,见 docs/v2-UPGRADE-GUIDE.md。
下文所有用法示例均以 3.x 为准。
常见用法
抓取纯文本或 HTML
import fetch from 'node-fetch';
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
response.text() 内部通过 consumeBody 把整个流累积为 Buffer,再交给 TextDecoder 解码为 UTF-8 字符串(见 src/body.js)。
抓取 JSON
import fetch from 'node-fetch';
const response = await fetch('https://api.github.com/users/github');
const data = await response.json();
console.log(data);
json() 是 text() + JSON.parse 的语法糖(见 src/body.js),如果响应体不是合法 JSON 会抛出解析异常。
简单 POST
import fetch from 'node-fetch';
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: 'a=1'});
const data = await response.json();
console.log(data);
POST JSON
import fetch from 'node-fetch';
const body = {a: 1};
const response = await fetch('https://httpbin.org/post', {
method: 'post',
body: JSON.stringify(body),
headers: {'Content-Type': 'application/json'}
});
const data = await response.json();
console.log(data);
这里显式设置 Content-Type: application/json。需要留意的是:请求方法名不区分大小写——在 src/request.js 中,delete/get/head/options/post/put 会被自动规范化为大写。
POST 表单参数
URLSearchParams 自 Node.js v10.0.0 起就是全局对象,可直接使用。
import fetch from 'node-fetch';
const params = new URLSearchParams();
params.append('a', 1);
const response = await fetch('https://httpbin.org/post', {method: 'POST', body: params});
const data = await response.json();
console.log(data);
注意:只有当你传入的 body 是 URLSearchParams 实例时,Content-Type 才会被自动设为 x-www-form-urlencoded。这个逻辑在 src/body.js 的 extractContentType 中实现,且带 ;charset=UTF-8 后缀。
异常处理
重要:3xx-5xx 状态码响应不是异常,必须放在 then() / 结果判断里处理,详见下一节。用 try/catch 包裹能捕获的所有异常包括:来自 Node 核心库的错误(如网络错误)、以及 FetchError 实例的操作类错误。完整错误体系见 docs/ERROR-HANDLING.md。
import fetch from 'node-fetch';
try {
await fetch('https://domain.invalid/');
} catch (error) {
console.log(error);
}
从源码看,fetch 内部在请求失败时会把底层错误包装成 FetchError(type: 'system')并 reject,见 src/index.js。
处理客户端与服务端错误(4xx/5xx)
实践中常写一个辅助函数检查响应状态:
import fetch from 'node-fetch';
class HTTPResponseError extends Error {
constructor(response) {
super(`HTTP Error Response: ${response.status} ${response.statusText}`);
this.response = response;
}
}
const checkStatus = response => {
if (response.ok) {
// response.status >= 200 && response.status < 300
return response;
} else {
throw new HTTPResponseError(response);
}
}
const response = await fetch('https://httpbin.org/status/400');
try {
checkStatus(response);
} catch (error) {
console.error(error);
const errorBody = await error.response.text();
console.error(`Error body: ${errorBody}`);
}
response.ok 是一个便捷属性,其实现为 status >= 200 && status < 300,见 src/response.js。
处理 Cookie
node-fetch 默认不存储 Cookie。你可以通过手动读取响应头中的 Set-Cookie、再在后续请求中构造 Cookie 请求头来实现会话维持,具体读取方法见下文"提取 Set-Cookie 头"。
高级用法
流式下载
"Node 风格"是尽量使用流。可以把 res.body 直接 pipe 到另一个流。下面的例子使用 stream.pipeline 挂接流错误处理并等待下载完成:
import {createWriteStream} from 'node:fs';
import {pipeline} from 'node:stream';
import {promisify} from 'node:util'
import fetch from 'node-fetch';
const streamPipeline = promisify(pipeline);
const response = await fetch('https://github.githubassets.com/images/modules/logos_page/Octocat.png');
if (!response.ok) throw new Error(`unexpected response ${response.statusText}`);
await streamPipeline(response.body, createWriteStream('./octocat.png'));
在 Node.js 14 中还可以用 async iterator 读取 body,但要注意捕获错误——响应运行时间越长,越可能遇到错误:
import fetch from 'node-fetch';
const response = await fetch('https://httpbin.org/stream/3');
try {
for await (const chunk of response.body) {
console.dir(JSON.parse(chunk.toString()));
}
} catch (err) {
console.error(err.stack);
}
在 Node.js 12 中 async iterator 也可用,但流的 async iteration 直到 Node.js 14 才成熟,需要额外处理流错误并等待响应完全关闭:
import fetch from 'node-fetch';
const read = async body => {
let error;
body.on('error', err => {
error = err;
});
for await (const chunk of body) {
console.dir(JSON.parse(chunk.toString()));
}
return new Promise((resolve, reject) => {
body.on('close', () => {
error ? reject(error) : resolve();
});
});
};
try {
const response = await fetch('https://httpbin.org/stream/3');
await read(response.body);
} catch (err) {
console.error(err.stack);
}
访问响应头与元数据
import fetch from 'node-fetch';
const response = await fetch('https://github.com/');
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers.raw());
console.log(response.headers.get('content-type'));
Headers.raw() 是 node-fetch 独有的非规范方法,返回 Record<string, string<a href="https://link.gitcode.com/i/e01f9c033e97a3232ce95fe1e64f3a3f" target="_blank">]>(见 [src/headers.js),能拿到同一 header 名的全部原始值数组。
提取 Set-Cookie 头
与浏览器不同,node-fetch 可以手动访问原始的 Set-Cookie 头:
import fetch from 'node-fetch';
const response = await fetch('https://example.com');
// 返回一个数组,而不是逗号拼接的字符串
console.log(response.headers.raw()['set-cookie']);
这与 Headers.get() 的行为不同:get() 会把同一名字的多个值用 ', ' 拼接(见 src/headers.js),而 raw() 保留独立条目——这正是提取多个 Set-Cookie 的关键。
用文件作为 POST 数据
node-fetch 自带符合规范的 Blob/File 实现,可以直接从本地文件构造请求体:
import fetch, {
Blob,
blobFrom,
blobFromSync,
File,
fileFrom,
fileFromSync,
} from 'node-fetch'
const mimetype = 'text/plain'
const blob = fileFromSync('./input.txt', mimetype)
const url = 'https://httpbin.org/post'
const response = await fetch(url, { method: 'POST', body: blob })
const data = await response.json()
console.log(data)
fileFromSync/fileFrom 与 blobFromSync/blobFrom 由 fetch-blob 提供并在 src/index.js 中统一导出,分别对应同步与异步两种创建方式。
用 FormData 提交 multipart/form-data
node-fetch 附带规范兼容的 FormData 实现,用于提交 multipart/form-data:
import fetch, { FormData, File, fileFrom } from 'node-fetch'
const httpbin = 'https://httpbin.org/post'
const formData = new FormData()
const binary = new Uint8Array([ 97, 98, 99 ])
const abc = new File([binary], 'abc.txt', { type: 'text/plain' })
formData.set('greeting', 'Hello, world!')
formData.set('file-upload', abc, 'new name.txt')
const response = await fetch(httpbin, { method: 'POST', body: formData })
const data = await response.json()
console.log(data)
在源码中,FormData 请求体会被自动转换为带 boundary 的 Blob,并据此生成 multipart/form-data; boundary=... 的 Content-Type(见 src/body.js 与 src/body.js)。
追加"类 Blob/File"对象:如果需要在任意位置产生一个流并塞进 FormData,可以追加一个"看起来像" Blob 或 File 的对象,最低要求是:
- 具有值为
Blob或File的Symbol.toStringTaggetter 或属性; - 有一个已知的
size; - 提供
stream()方法(返回产出 Uint8Array/Buffer 的任意 async iterable)或arrayBuffer()方法(返回 ArrayBuffer)。
formData.append('upload', {
[Symbol.toStringTag]: 'Blob',
size: 3,
*stream() {
yield new Uint8Array([97, 98, 99])
},
arrayBuffer() {
return new Uint8Array([97, 98, 99]).buffer
}
}, 'abc.txt')
只要 stream() 产出 Uint8Array(或 Buffer),Node.js Readable 流和 whatwg streams 都能直接使用。
用 AbortSignal 取消请求
通过 AbortController 可以随时取消请求,推荐的 polyfill 实现是 abort-controller。下面的例子演示 150ms 超时取消:
import fetch, { AbortError } from 'node-fetch';
// AbortController 从 node v14.17.0 起成为全局对象
const AbortController = globalThis.AbortController || await import('abort-controller')
const controller = new AbortController();
const timeout = setTimeout(() => {
controller.abort();
}, 150);
try {
const response = await fetch('https://example.com', {signal: controller.signal});
const data = await response.json();
} catch (error) {
if (error instanceof AbortError) {
console.log('request was aborted');
}
} finally {
clearTimeout(timeout);
}
源码层面的取消链路在 src/index.js:fetch 在收到 abort 事件后会 reject 一个 AbortError,销毁尚未完成的请求体流,并向响应体发出 error 事件;如果 signal 在调用前已处于 aborted 状态,则会立即中止。更多取消场景的测试用例见仓库的 test 目录。
API 参考
fetch(url[, options])
url:表示要请求的 URL 的字符串;options:HTTP(S) 请求的 Options;- 返回:
Promise<Response>。
url 必须是绝对 URL(如 https://example.com/)。路径相对 URL(/file/under/root)或协议相对 URL(//can-be-http-or-https.com/)会导致 Promise 被 reject。
从 src/index.js 的实现看,fetch 内部支持 data:、http:、https: 三种协议:非支持协议直接抛出 TypeError,data: URL 则通过 data-uri-to-buffer 直接构造 Response 返回,无需真实网络请求。
Options
默认值紧随各选项键后展示:
{
// 以下属性属于 Fetch 标准
method: 'GET',
headers: {}, // 请求头,格式与 Headers 构造函数接受的格式一致
body: null, // 请求体,可以是 null 或 Node.js Readable 流
redirect: 'follow', // 设为 manual 可提取重定向头,设为 error 则拒绝重定向
signal: null, // 传入 AbortSignal 实例以可选地中止请求
// 以下属性是 node-fetch 扩展
follow: 20, // 最大重定向次数,0 表示不跟随重定向
compress: true, // 支持 gzip/deflate 内容编码,false 则禁用
size: 0, // 最大响应体字节数,0 表示不限制
agent: null, // http(s).Agent 实例或返回实例的函数
highWaterMark: 16384, // 内部缓冲区最大字节数,超过则暂停从底层资源读取
insecureHTTPParser: false // 为 true 时使用接受非法 HTTP 头的不安全解析器
}
这些扩展选项在 src/request.js 中逐一落地:follow 默认 20、compress 默认 true、counter 默认 0、highWaterMark 默认 16384、insecureHTTPParser 默认 false,并支持从被克隆的 Request 上继承。
默认请求头
未显式设置时,node-fetch 会自动发送以下请求头:
| Header | Value |
|---|---|
Accept-Encoding |
gzip, deflate, br (当 options.compress === true) |
Accept |
*/* |
Content-Length |
(可计算时自动算出) |
Host |
(目标 URI 的 host 与 port 信息) |
Transfer-Encoding |
chunked (当 req.body 是流时) |
User-Agent |
node-fetch |
注意:当 body 是流时,Content-Length 不会被自动设置(因为流长度未知)。这些默认头在 src/request.js 的 getNodeRequestOptions 中按条件填充:Accept 缺失时补 */*、POST/PUT 且无 body 时补 Content-Length: 0、已知长度的 body 填实际字节数、User-Agent 缺失时补 node-fetch、开启 compress 且无 Accept-Encoding 时补 gzip, deflate, br。
自定义 Agent
agent 选项允许指定超出 Fetch 规范范围的网络相关配置,包括但不限于:
- 支持自签名证书;
- 仅使用 IPv4 或 IPv6;
- 自定义 DNS 查询。
若未指定 agent,则使用 Node.js 默认 agent。注意 Node.js 19 起默认 agent 的 keepalive 变为 true;在更早版本中想要启用 keepalive,可以按下面代码覆盖 agent。
此外,agent 选项接受一个函数,给定当前 URL 返回 http(s).Agent 实例——这在跨 HTTP/HTTPS 协议的重定向链中非常有用:
import http from 'node:http';
import https from 'node:https';
const httpAgent = new http.Agent({
keepAlive: true
});
const httpsAgent = new https.Agent({
keepAlive: true
});
const options = {
agent: function(_parsedURL) {
if (_parsedURL.protocol == 'http:') {
return httpAgent;
} else {
return httpsAgent;
}
}
};
函数形式的 agent 会在 src/request.js 中按当前解析后的 URL 协议动态求值。
自定义 highWaterMark
Node.js 流的内部缓冲区较小(16kB,即默认 highWaterMark),而浏览器端普遍大于 1MB 且各浏览器不一致。因此在编写 isomorphic 应用并使用 res.clone() 时,大响应在 Node 端可能挂起。
推荐做法是并行消费克隆后的响应:
import fetch from 'node-fetch';
const response = await fetch('https://example.com');
const r1 = response.clone();
const results = await Promise.all([response.json(), r1.text()]);
console.log(results[0]);
console.log(results[1]);
如果不喜欢上述方案,从 3.x 起可以显式调大 highWaterMark:
import fetch from 'node-fetch';
const response = await fetch('https://example.com', {
// 约 1MB
highWaterMark: 1024 * 1024
});
const result = await res.clone().arrayBuffer();
console.dir(result);
highWaterMark 会同时作用于响应体流与克隆时的两个 PassThrough 流(见 src/body.js 的 clone 实现与 src/response.js 的 Response.clone)。
不安全 HTTP 解析器(Insecure HTTP Parser)
insecureHTTPParser 选项会原样透传给 http(s).request 的同名选项,为 true 时使用接受非法 HTTP 头的宽松解析器,具体语义可查阅 Node.js http.request 文档。
手动处理重定向
node-fetch 的 redirect: 'manual' 与浏览器/规范不同:规范中会得到 opaque-redirect 过滤响应,而 node-fetch 返回的是普通的基本过滤响应,让你可以读取重定向响应的头与状态:
import fetch from 'node-fetch';
const response = await fetch('https://httpbin.org/status/301', { redirect: 'manual' });
if (response.status === 301 || response.status === 302) {
const locationURL = new URL(response.headers.get('location'), response.url);
const response2 = await fetch(locationURL, { redirect: 'manual' });
console.dir(response2);
}
跟随模式的重定向逻辑在 src/index.js 中实现:error 模式直接 reject no-redirect 类型的 FetchError;follow 模式会检查 follow 上限(超限 reject max-redirect)、跨域/跨协议时移除 authorization、www-authenticate、cookie、cookie2 等敏感头、303 或 301/302 跟随 POST 时降级为 GET 并清空 body 与 content-length。
Class: Request
Request 封装 HTTP(S) 请求的 URL、方法、头与 body 信息,实现了 Body 接口。
由于 Node.js 的运行时特性,以下属性目前未实现:
typedestinationmodecredentialscacheintegritykeepalive
以下 node-fetch 扩展属性已提供:
followcompresscounteragenthighWaterMark
其含义与上文 Options 中的同名扩展一致。
new Request(input[, options])
(符合规范)
input:URL 字符串,或另一个Request(会被克隆);options:HTTP(S) 请求的 Options。
构造器与浏览器版 Request 一致。多数场景直接 fetch(url, options) 比先建 Request 对象更简洁。
在 src/request.js 中可以看到构造器的重要约束:URL 不允许内嵌用户名/密码(会抛 TypeError);GET/HEAD 方法不允许携带 body(会抛 TypeError);signal 必须是 AbortSignal 或 EventTarget;referrer 为 '' 时等价于 'no-referrer'。
Class: Response
Response 封装 HTTP(S) 响应,实现了 Body 接口。当前未实现 trailer 属性。
new Response([body[, options]])
(符合规范)
body:String或Readable流;options:ResponseInit选项字典。
构造器与浏览器版 Response 一致。由于 Node.js 没有 Service Worker(该类本为它设计),日常极少需要直接构造 Response。源码中 status 缺省为 200,body 非空且无 Content-Type 时会自动推导类型(见 src/response.js)。
此外 src/response.js 还提供了三个静态工厂方法:
Response.redirect(url, status = 302):构造携带location头的重定向响应,非重定向状态码会抛RangeError;Response.error():构造type: 'error'、状态 0 的响应;Response.json(data, init):将数据序列化为 JSON 并自动设置content-type: application/json。
response.ok
(符合规范)
表示请求是否正常结束的便捷属性:状态码 ≥ 200 且 < 300 时为 true。
response.redirected
(符合规范)
表示请求是否至少被重定向过一次:内部重定向计数器大于 0 时为 true(见 src/response.js,基于 counter 实现)。
response.type
(与规范的偏差)
表示响应类型的便捷属性。node-fetch 仅支持 'default' 与 'error' 两种,不使用规范中的过滤响应机制。
Class: Headers
Headers 类用于操作和遍历一组 HTTP 头,实现了 Fetch 标准规定的全部方法。
new Headers([init])
(符合规范)
init:可选,预填充Headers对象。
init 可以是 null、另一个 Headers 对象、键值对映射对象或任意可迭代对象:
// 示例改编自 https://fetch.spec.whatwg.org/#example-headers-class
import {Headers} from 'node-fetch';
const meta = {
'Content-Type': 'text/xml'
};
const headers = new Headers(meta);
// 以上写法等价于:
const meta = [['Content-Type', 'text/xml']];
const headers = new Headers(meta);
// 事实上任何可迭代对象都可以,比如 Map 甚至是另一个 Headers
const meta = new Map();
meta.set('Content-Type', 'text/xml');
const headers = new Headers(meta);
const copyOfHeaders = new Headers(headers);
从实现看,src/headers.js 的 Headers 继承自 URLSearchParams:构造时统一校验 header 名/值合法性、把名字小写化,并返回一个 Proxy 以保证 append/set/delete/has/getAll 都经过校验与小写化、keys() 前自动排序。raw() 与 getAll() 的组合是提取多值头(如 Set-Cookie)的官方途径。
Interface: Body
Body 是对 Request 和 Response 都适用的抽象接口,提供以下成员。
body.body
(与规范的偏差)
- Node.js
Readable流。
数据封装在 Body 对象中。Fetch 标准要求该属性恒为 WHATWG ReadableStream,而 node-fetch 中它是 Node.js 的 Readable 流(见 src/body.js)。
body.bodyUsed
(符合规范)
Boolean
表示该 body 是否已被消费。按规范,已消费的 body 不能再次使用;重复调用消费方法会抛出 TypeError: body used already for: ...(见 src/body.js)。
body.arrayBuffer()
异步把整个 body 读为 ArrayBuffer。
body.formData()
解析 multipart/form-data 或 x-www-form-urlencoded 负载为 FormData。这个能力源于 Service Worker 可以在请求发送到服务器前拦截并修改消息的思想,对搭建服务端、解析消费负载的人尤其有用:
import http from 'node:http'
import { Response } from 'node-fetch'
http.createServer(async function (req, res) {
const formData = await new Response(req, {
headers: req.headers // 传递 boundary 值
}).formData()
const allFields = [...formData]
const file = formData.get('uploaded-files')
const arrayBuffer = await file.arrayBuffer()
const text = await file.text()
const whatwgReadableStream = file.stream()
// 消费请求的其他方式:
const json = await new Response(req).json()
const text = await new Response(req).text()
const arrayBuffer = await new Response(req).arrayBuffer()
const blob = await new Response(req, {
headers: req.headers // 让 type 继承 Content-Type
}).blob()
})
在 src/body.js 的实现中,formData() 会根据 content-type 分流:application/x-www-form-urlencoded 走 URLSearchParams 转换,multipart 则交给 src/utils/multipart-parser.js 的解析器。
body.blob()
异步把整个 body 读为 Blob,其 type 继承响应的 Content-Type。
body.json()
异步把整个 body 解析为 JSON(text() + JSON.parse)。
body.text()
异步把整个 body 解码为 UTF-8 字符串。
另外需要注意:消费时若超出 size 限制,consumeBody 会销毁流并抛出 type: 'max-size' 的 FetchError(见 src/body.js),这是 size 选项的底层实现。
Class: FetchError
(node-fetch 扩展)
抓取过程中的操作类错误,所有非中止类操作错误都会以 FetchError 形式 reject。它继承自 FetchBaseError(见 src/errors/base.js),并带有 type 属性;当类型为 system 时,还会从 Node.js 系统错误上拷贝 code、errno 与 erroredSysCall(见 src/errors/fetch-error.js)。完整分类见 docs/ERROR-HANDLING.md。
Class: AbortError
(node-fetch 扩展)
响应 AbortSignal 的 abort 事件、请求被中止时抛出的错误,其 name 属性为 AbortError(见 src/errors/abort-error.js)。
错误处理体系
因为 window.fetch 并不透明地说明请求失败的成因,node-fetch 建立了自己的错误约定,详见 docs/ERROR-HANDLING.md,要点如下:
- 被取消的请求以
AbortErrorreject,可通过检查error.name === 'AbortError'判断是否为中止导致的失败:
try {
await fetch(url, {signal});
} catch (error) {
if (error.name === 'AbortError') {
console.log('request was aborted');
}
}
- 除中止外的所有操作类错误都以
FetchErrorreject,统一通过try/catch或 Promise 的catch处理; - 所有错误都带
error.message说明成因; - 所有来自 node-fetch 的错误都有自定义的
err.type标记; - 所有源自 Node.js 核心的错误标记为
error.type = 'system',并额外提供error.code与error.errno(与 Node.js 核心抛出的错误码互为别名)供精细化处理; - 编程错误(programmer errors)则尽早抛出,或用带
error.message的默认Errorreject,方便排查。
仓库维护 100% 覆盖率,完整的自定义 FetchError 类型清单与常见 Node.js 错误可见 test/main.js。
TypeScript 支持
从 3.x 起类型定义随 node-fetch 一并发布,无需再安装额外类型包。 类型文件位于 @types/index.d.ts,覆盖 fetch、Headers、Request、Response、Body、FetchError、AbortError 以及 Blob/File/FormData 等导出,并完整声明了 RequestInit 中 agent、compress、follow、size、highWaterMark、insecureHTTPParser 等 node-fetch 扩展选项。
对于旧版本,请使用 DefinitelyTyped 的类型定义:
npm install --save-dev @types/node-fetch@2.x
许可证
node-fetch 采用 MIT 许可证,全文见 LICENSE.md。
提示:本文所述用法均基于当前仓库的
3.x代码(版本号见 package.json),data:URL 支持、敏感头跨域重定向剥离、流式 formData 解析等行为以源码实现为准;文中示例涉及的 httpbin 等外部服务仅用于演示,生产环境请替换为真实接口。