可用于在 Node.js 环境中发起 HTTP 请求,实现与浏览器 fetch API 兼容的功能。支持原生 promise、异步函数及 Node 流,能自动解码内容编码,提供重定向限制、响应大小限制等实用扩展。【此简介由AI生成】
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 2 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 1 年前 | ||
| 2 年前 | ||
| 2 年前 | ||
| 2 年前 |
您可能正在查看 v2 版本文档
- 初衷
- 特性
- 与客户端 fetch 的区别
- 安装
- 加载与配置模块
- 升级指南
- 常见用法
- 高级用法
- API 文档
- TypeScript 支持
- 致谢
- 团队 - 往期成员
- 许可证
初衷
与其在 Node.js 中实现 XMLHttpRequest 来运行浏览器专用的 Fetch 垫片,何不直接从原生 http 模块过渡到 fetch API?因此诞生了 node-fetch,它以最简代码在 Node.js 运行时实现了与 window.fetch 兼容的 API。
如需同构使用(服务端导出 node-fetch,客户端导出 whatwg-fetch),可参考 Jason Miller 的 isomorphic-unfetch 或 Leonardo Quixada 的 cross-fetch。
特性
- 严格遵循
window.fetchAPI 规范 - 在实现 WHATWG fetch 标准 和 流处理标准 时做出合理取舍,并记录已知差异
- 基于原生 Promise 和异步函数实现
- 请求与响应体均采用 Node 原生流处理
- 自动解压内容编码(gzip/deflate/brotli),并将字符串输出(如
res.text()和res.json())自动转换为 UTF-8 编码 - 提供实用扩展功能:重定向限制、响应大小限制、明确的错误类型 便于问题排查
与客户端 fetch 的区别
安装
当前稳定版(3.x)要求 Node.js 版本至少为 12.20.0。
npm install node-fetch
加载与配置模块
ES 模块 (ESM)
import fetch from 'node-fetch';
CommonJS
从 v3 版本开始,node-fetch 仅支持 ESM 模块规范——无法通过 require() 导入该模块。
若您暂时无法迁移至 ESM 规范,请继续使用兼容 CommonJS 的 v2 版本。针对 v2 版本的关键错误修复仍将持续发布。
npm install node-fetch@2
或者,你也可以使用 CommonJS 中的异步 import() 函数来动态加载 node-fetch:
// mod.cjs
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
提供全局访问
要在不导入的情况下使用 fetch(),可以在 node 中修补 global 对象:
// 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'
// ...
升级指南
正在使用旧版 node-fetch?请查阅以下文件:
常见用法
注意:以下文档针对 3.x 版本保持最新,若您使用的是旧版,请查看如何升级。
纯文本或 HTML 请求
import fetch from 'node-fetch';
const response = await fetch('https://github.com/');
const body = await response.text();
console.log(body);
JSON
import fetch from 'node-fetch';
const response = await fetch('https://api.github.com/users/github');
const data = await response.json();
console.log(data);
简单文章
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);
使用 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);
带表单参数的 POST 请求
从 Node.js v10.0.0 开始,全局对象中提供了 URLSearchParams。更多使用方法请参阅官方文档。
注意:只有当 URLSearchParams 实例直接作为参数传递时,Content-Type 头才会自动设置为 x-www-form-urlencoded:
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);
异常处理
注意:3xx-5xx 响应不属于异常,应在 then() 中处理,详见下一节。
将 fetch 函数包裹在 try/catch 代码块中,可以捕获所有异常,包括源自 Node 核心库的错误(如网络错误)以及属于 FetchError 实例的操作错误。更多细节请参阅错误处理文档。
import fetch from 'node-fetch';
try {
await fetch('https://domain.invalid/');
} catch (error) {
console.log(error);
}
处理客户端与服务器错误
通常我们会创建一个辅助函数,用于检查响应是否包含客户端(4xx)或服务器(5xx)错误:
def check_response(response):
"""验证响应状态码是否属于错误范围"""
if 400 <= response.status_code < 500:
raise ClientError(f"客户端错误: {response.status_code}")
elif 500 <= response.status_code < 600:
raise ServerError(f"服务器错误: {response.status_code}")
return response
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}`);
}
处理 Cookie
默认情况下,系统不会存储 Cookie。但通过操作请求头和响应头,可以提取并传递 Cookie。具体方法请参阅 提取 Set-Cookie 头信息。
高级用法
流处理
"Node.js 风格"的核心在于尽可能使用流式操作。您可以将 res.body 通过管道传输到另一个流中。以下示例使用 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 中,你也可以使用异步迭代器来读取 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 中,你也可以使用异步迭代器来读取 body;然而,流式异步迭代器直到 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'));
提取 Set-Cookie 头部信息
与浏览器不同,您可以通过 Headers.raw() 方法手动访问原始的 Set-Cookie 头部信息。这是 node-fetch 独有的 API。
import fetch from 'node-fetch';
const response = await fetch('https://example.com');
// Returns an array of values, instead of a string of comma-separated values
console.log(response.headers.raw()['set-cookie']);
使用文件提交数据
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)
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)
若因某些原因需要发布来自任意位置的流数据, 可附加一个类似 Blob 或 File 的对象。
最低要求是具备:
- 拥有
Symbol.toStringTag的 getter 或属性,其值为Blob或File - 已知大小
- 提供
stream()方法或arrayBuffer()方法,后者需返回 ArrayBuffer
其中 stream() 方法需返回任意异步可迭代对象,只要其生成 Uint8Array(或 Buffer)即可,
因此 Node.Readable 流和 whatwg 流均能完美兼容。
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')
使用 AbortSignal 取消请求
你可以通过 AbortController 来取消请求。推荐的实现方式是使用 abort-controller。
以下是一个在 150 毫秒后超时取消请求的示例实现:
import fetch, { AbortError } from 'node-fetch';
// AbortController was added in node v14.17.0 globally
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);
}
请参考测试用例获取更多示例。
API
fetch(url[, options])
执行HTTP(S)请求。
url应为绝对URL,例如https://example.com/。若使用路径相对URL(/file/under/root)或协议相对URL(//can-be-http-or-https.com/),将导致返回被拒绝的Promise。
配置项
各配置键的默认值显示在对应选项之后。
{
// These properties are part of the Fetch Standard
method: 'GET',
headers: {}, // Request headers. format is the identical to that accepted by the Headers constructor (see below)
body: null, // Request body. can be null, or a Node.js Readable stream
redirect: 'follow', // Set to `manual` to extract redirect headers, `error` to reject redirect
signal: null, // Pass an instance of AbortSignal to optionally abort requests
// The following properties are node-fetch extensions
follow: 20, // maximum redirect count. 0 to not follow redirect
compress: true, // support gzip/deflate content encoding. false to disable
size: 0, // maximum response body size in bytes. 0 to disable
agent: null, // http(s).Agent instance or function that returns an instance (see below)
highWaterMark: 16384, // the maximum number of bytes to store in the internal buffer before ceasing to read from the underlying resource.
insecureHTTPParser: false // Use an insecure HTTP parser that accepts invalid HTTP headers when `true`.
}
默认请求头
若未设置任何值,以下请求头将自动发送:
| 请求头 | 值 |
|---|---|
Accept-Encoding |
gzip, deflate, br(当 options.compress === true 时启用) |
Accept |
*/* |
Content-Length |
(自动计算,若条件允许) |
Host |
(根据目标 URI 自动填充主机和端口信息) |
Transfer-Encoding |
chunked(当 req.body 为流式数据时启用) |
User-Agent |
node-fetch |
注意:当 body 为 Stream 类型时,Content-Length 不会自动设置。
自定义代理
通过 agent 选项可配置网络相关参数,这些配置超出 Fetch 标准范围,包括但不限于以下场景:
- 支持自签名证书
- 强制使用 IPv4 或 IPv6
- 自定义 DNS 查询
详见 http.Agent 文档。
若未指定代理,将使用 Node.js 提供的默认代理。注意 Node.js 19 版本 开始默认启用 keepalive。如需在早期版本启用该功能,可参考以下代码示例覆盖代理配置。
此外,agent 选项支持接收函数,该函数根据当前 URL 返回 http 或 https 的 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;
}
}
};
自定义高水位线
Node.js 中的流相较于客户端浏览器(大于 1MB,不同浏览器间不一致)具有较小的内部缓冲区大小(16KB,即 highWaterMark)。因此,当你在编写同构应用并使用 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', {
// About 1MB
highWaterMark: 1024 * 1024
});
const result = await res.clone().arrayBuffer();
console.dir(result);
不安全的 HTTP 解析器
该选项会透传给 http(s).request 的 insecureHTTPParser 参数。更多信息请参阅 http.request 文档。
手动重定向
当设置 redirect: 'manual' 选项时,node-fetch 的行为与浏览器及规范有所不同:
- 按照规范应返回不透明重定向过滤响应
- 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);
}
类:Request
一个包含 URL、方法、标头和正文信息的 HTTP(S) 请求。该类实现了 Body 接口。
由于 Node.js 的特性,以下属性目前未实现:
typedestinationmodecredentialscacheintegritykeepalive
提供了以下 node-fetch 扩展属性:
followcompresscounteragenthighWaterMark
这些扩展的具体含义请参见 options。
new Request(input[, options])
(符合规范)
input表示 URL 的字符串,或另一个将被克隆的Request对象optionsHTTP(S) 请求的 选项
构造一个新的 Request 对象。该构造函数与 浏览器 中的相同。
大多数情况下,直接使用 fetch(url, options) 比创建 Request 对象更简单。
类:Response
一个 HTTP(S) 响应。该类实现了 Body 接口。
以下属性目前在 node-fetch 中未实现:
trailer
new Response([body[, options]])
(符合规范)
body一个String或Readable流options一个ResponseInit选项字典
构造一个新的 Response 对象。该构造函数与 浏览器 中的相同。
由于 Node.js 未实现服务工作者(该类专为此设计),很少需要直接构造 Response。
response.ok
(符合规范)
表示请求是否正常结束的便捷属性。如果响应状态码大于等于 200 且小于 300,则为 true。
response.redirected
(符合规范)
表示请求是否至少被重定向过一次的便捷属性。如果内部重定向计数器大于 0,则为 true。
response.type
(与规范有差异)
表示响应类型的便捷属性。node-fetch 仅支持 'default' 和 'error',且未使用 过滤响应。
类:Headers
该类允许操作和遍历一组 HTTP 标头。实现了 Fetch 标准 中指定的所有方法。
new Headers([init])
(符合规范)
init可选参数,用于预填充Headers对象
构造一个新的 Headers 对象。init 可以是 null、Headers 对象、键值映射对象或任何可迭代对象。
// Example adapted from https://fetch.spec.whatwg.org/#example-headers-class
import {Headers} from 'node-fetch';
const meta = {
'Content-Type': 'text/xml'
};
const headers = new Headers(meta);
// The above is equivalent to
const meta = [['Content-Type', 'text/xml']];
const headers = new Headers(meta);
// You can in fact use any iterable objects, like a Map or even another Headers
const meta = new Map();
meta.set('Content-Type', 'text/xml');
const headers = new Headers(meta);
const copyOfHeaders = new Headers(headers);
接口: Body
Body 是一个抽象接口,其方法适用于 Request 和 Response 类。
body.body
(与规范差异)
- Node.js
Readable流
数据封装在 Body 对象中。请注意,虽然 Fetch 标准 要求该属性始终为 WHATWG ReadableStream,但在 node-fetch 中,它是一个 Node.js Readable 流。
body.bodyUsed
(符合规范)
Boolean
一个布尔属性,表示此 body 是否已被消费。根据规范,已消费的 body 不能再次使用。
body.arrayBuffer()
body.formData()
body.blob()
body.json()
body.text()
fetch 提供了方法来解析 multipart/form-data 负载以及使用 .formData() 解析 x-www-form-urlencoded 的 body。这一设计源于 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 // Pass along the boundary value
}).formData()
const allFields = [...formData]
const file = formData.get('uploaded-files')
const arrayBuffer = await file.arrayBuffer()
const text = await file.text()
const whatwgReadableStream = file.stream()
// other was to consume the request could be to do:
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 // So that `type` inherits `Content-Type`
}.blob()
})
类:FetchError
(node-fetch 扩展)
在数据获取过程中出现的操作错误。更多信息请参阅 ERROR-HANDLING.md。
类:AbortError
(node-fetch 扩展)
当请求因响应 AbortSignal 的 abort 事件而中止时抛出的错误。其 name 属性为 AbortError。更多详情请参见 ERROR-HANDLING.MD。
TypeScript 支持
自 3.x 版本起,类型定义已内置在 node-fetch 中,无需额外安装类型包。
对于旧版本,请使用 DefinitelyTyped 提供的类型定义:
npm install --save-dev @types/node-fetch@2.x
致谢
感谢 github/fetch 提供了坚实的实现参考。
团队
![]() |
![]() |
![]() |
![]() |
![]() |
|---|---|---|---|---|
| David Frank | Jimmy Wärting | Antoni Kepinski | Richie Bendall | Gregor Martynus |
前成员
许可证
项目介绍
可用于在 Node.js 环境中发起 HTTP 请求,实现与浏览器 fetch API 兼容的功能。支持原生 promise、异步函数及 Node 流,能自动解码内容编码,提供重定向限制、响应大小限制等实用扩展。【此简介由AI生成】
定制我的领域




