# 在 Node.js fetch 中使用代理

Source: https://ipvolt.com/zh/guides/nodejs-fetch-proxy
Markdown: https://ipvolt.com/zh/guides/nodejs-fetch-proxy.md
Language: zh-CN

[ipvolt 首页](https://ipvolt.com/zh.md) / [指南](https://ipvolt.com/zh/guides.md) / 在 Node.js fetch 中使用代理

集成
审校于: 2026-09-10
阅读约 4 分钟
作者： ipvolt

让 Node.js 原生 fetch 经由 Undici ProxyAgent 走代理，并配置显式的代理认证、中止期限和响应体清理。

## 起点

为单次 fetch 调用使用一个 dispatcher，使代理配置显式化，进程中的其他网络客户端则保留各自的配置。

## 选择兼容的运行时与 dispatcher

这个服务端示例面向 Node.js 24 和 Undici 7。在一个单独的示例项目中运行 npm install undici@7。Node 内置的 fetch 接受与 Undici 兼容的 dispatcher。这与浏览器中的 fetch 不同，页面 JavaScript 无法任意选择系统代理。

在 PROXY_URL 中使用提供商文档给出的 HTTP(S) 网关，例如刻意无法工作的 https://proxy.example.invalid:8443。通过部署环境的密钥管理器注入 PROXY_USERNAME 和 PROXY_PASSWORD。不要把网关凭据放进前端代码。

## 把代理认证放在 dispatcher 上

保存为 proxy-check.mjs 并运行 node proxy-check.mjs。Basic 令牌属于代理 agent，而不是目标站点的 Authorization 请求头。该请求有 30 秒的中止期限，并且不会自动跟随重定向。

### proxy-check.mjs · Node.js 24 + Undici 7

```javascript
import { ProxyAgent } from 'undici';

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error('Missing environment variable: ' + name);
  return value;
}

const gateway = new URL(required('PROXY_URL'));
if (!['http:', 'https:'].includes(gateway.protocol) || gateway.username || gateway.password) {
  throw new Error('Use a credential-free HTTP(S) proxy URL');
}
const credentials = required('PROXY_USERNAME') + ':' + required('PROXY_PASSWORD');
const dispatcher = new ProxyAgent({
  uri: gateway.href,
  token: 'Basic ' + Buffer.from(credentials).toString('base64'),
});

try {
  const response = await fetch('https://example.com/', {
    dispatcher,
    signal: AbortSignal.timeout(30_000),
    redirect: 'manual',
  });
  await response.body?.cancel();
  if (!response.ok) throw new Error('Destination HTTP ' + response.status);
  console.log({ status: response.status });
} finally {
  await dispatcher.close();
}
```

## 从诊断脚本走向工作进程

这个脚本刻意取消了响应体，因为诊断只需要状态码。使用结果的工作进程应在其预算内消费响应体。在继续之前务必消费或取消它，并在工作进程关闭时关闭 dispatcher。

对于重复的任务，复用一个并发受限的 dispatcher，而不是为每个请求创建一个。让每个任务的期限彼此独立。除非有意改变每个受影响客户端的路由，否则不要安装进程级的 dispatcher。

- HTTP 错误是一个响应；fetch 不会仅仅因为状态码是 4xx 或 5xx 而 reject。
- CONNECT 被拒绝可能在目标站点的 Response 存在之前就表现为 fetch 失败。
- 记录脱敏后的错误类别；不要记录 Basic 令牌或包含凭据的完整 URL。

## 上线之前

- 使用文档中给出的 Node 和 Undici 主版本。
- 显式传入 dispatcher。
- 消费或取消响应体，并关闭 agent。

## 参考来源与延伸阅读

- [Node.js: fetch and custom dispatchers](https://nodejs.org/api/globals.html#fetch)
- [Undici 7: ProxyAgent authentication and lifecycle](https://github.com/nodejs/undici/blob/v7.16.0/docs/docs/api/ProxyAgent.md)
- [Undici: runtime support and response body handling](https://github.com/nodejs/undici)

## 相关指南

- [在 curl 中使用代理：-x、环境变量、SOCKS5 与认证](https://ipvolt.com/zh/guides/curl-proxy-setup.md)
- [代理环境变量：HTTP_PROXY 与 NO_PROXY](https://ipvolt.com/zh/guides/proxy-environment-variables.md)
- [HTTP 与 SOCKS5 代理：按连接方式选择](https://ipvolt.com/zh/guides/http-vs-socks5-proxies.md)

## 关于 ipvolt

示例使用通用的代理设置，并附上原始技术文档链接。具体产品的行为请向你的服务商确认。ipvolt 仍在开发中。

[阅读英文原文](https://ipvolt.com/guides/nodejs-fetch-proxy.md)

## 了解何时开放体验。

ipvolt · 开发中

我们正在为开发者和数据团队打造代理基础设施。加入意向名单，ipvolt 就绪时第一时间收到通知。

开放体验时仅发一封通知邮件，不发送其他邮件。

[申请抢先体验](https://ipvolt.com/zh/guides/nodejs-fetch-proxy#waitlist-closing)

[隐私政策](https://ipvolt.com/privacy)

