Node.js fetch环境变量代理不生效?从版本、启动开关到 Undici 逐层排查
悟空代理IP 2026-09-13 218
在终端里设置了 HTTP_PROXY 或 HTTPS_PROXY,Node.js 的 fetch() 却仍然直连,是很多迁移项目会遇到的问题。原因通常不是代理 IP 失效,而是把“环境里存在代理地址”误当成了“当前 HTTP 客户端会自动读取它”。Node 内置 fetch 基于 Undici;是否读取环境变量,取决于 Node 版本、启动方式以及应用有没有换过全局 dispatcher。
本文只讨论企业出口、自有接口或已获授权业务的网络配置。代理用于受控转发,不代表拥有目标服务的访问许可,也不应用于规避访问规则。
先确认三个事实
排查前先记录 node -v、process.versions.undici、实际调用的是全局 fetch 还是 npm 包导出的 fetch。这三项决定后面的配置路径。
| 现象 | 常见原因 | 优先动作 |
|---|---|---|
环境变量存在,但全局 fetch 直连 |
未启用 Node 内置环境代理支持 | 核对版本和启动开关 |
curl 走代理,Node 不走 |
两者读取环境变量的规则不同 | 不用 curl 结果替代 Node 验收 |
| 部分地址直连 | NO_PROXY 命中,或大小写变量冲突 |
打印脱敏后的变量来源和命中规则 |
| 设置 dispatcher 后仍异常 | Undici 包版本与 Node 内置版本不匹配,或被后续代码覆盖 | 检查依赖版本及初始化顺序 |
不要在日志里输出完整代理 URL。若 URL 含用户名和密码,只保留协议、脱敏主机、端口及资源别名。
新版 Node 要显式启用环境代理
Node 官方文档显示,--use-env-proxy 在 Node 24.5.0 和 22.21.0 加入;NODE_USE_ENV_PROXY=1 也可启用启动时的环境代理解析。仅设置 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY,并不等于所有 Node 版本都会让内置 fetch 自动采用它们。
可把代理地址和开关都放在进程启动前:
HTTP_PROXY="http://proxy.example:8080" \
HTTPS_PROXY="http://proxy.example:8080" \
NO_PROXY="localhost,127.0.0.1,.internal.example" \
node --use-env-proxy app.mjs
也可以设置 NODE_USE_ENV_PROXY=1 后启动进程。关键点是“启动前”:不要在第一次请求之后才修改变量,并期待已经创建的全局代理配置自动重建。当前官方仍将这项内置代理支持标为活跃开发,生产环境应固定 Node 小版本并做回归测试。
Node 24.14.0、25.4.0 及更高对应版本还提供 http.setGlobalProxyFromEnv(),可在运行时重置全局 http、https agent 和 Undici dispatcher。它会覆盖先前的全局配置,应在任何请求发出前调用,不要在并发请求中切换:
import { setGlobalProxyFromEnv } from 'node:http';
setGlobalProxyFromEnv();
const response = await fetch(process.env.HEALTHCHECK_URL);
console.log({ status: response.status });
如果当前版本没有这个 API,不要照抄;应采用启动开关,或选择与项目 Node 版本兼容的 Undici 方案。
旧版或显式 Undici 用 EnvHttpProxyAgent
对于尚未提供内置环境代理开关的 Node 版本,或代码明确从 undici 导入 fetch,可以安装与当前 Node 兼容的 Undici 版本,并注册 EnvHttpProxyAgent:
import {
EnvHttpProxyAgent,
fetch,
setGlobalDispatcher,
} from 'undici';
const dispatcher = new EnvHttpProxyAgent();
setGlobalDispatcher(dispatcher);
try {
const response = await fetch(process.env.HEALTHCHECK_URL);
console.log({ status: response.status });
} finally {
await dispatcher.close();
}
Undici 文档说明,EnvHttpProxyAgent 会读取大小写形式的代理变量;大小写同时存在时,小写值优先。NO_PROXY=* 会绕过所有代理,域名或端口规则写错也可能造成“只有某些请求不生效”。如果只给单次请求指定 dispatcher,就不要再假设全局 fetch 会继承同样配置。
用两组受控请求验证是否真的生效
准备一个团队自有的出口检查地址,分别在直连和代理条件下请求;固定目标 URL、Node 版本、超时值和时间窗口,只改变代理开关。记录状态码、耗时、脱敏出口标识和是否命中 NO_PROXY,不要记录响应中的敏感数据。
若开启代理后出口仍不变,先检查进程实际环境、Node 启动参数和 dispatcher 初始化顺序;若返回 407,说明代理已经响应,应核对账密、白名单和订单归属;若是连接超时,再查代理主机、端口、协议、DNS 与防火墙。超时分层可参考axios代理请求超时排查,基础字段可结合代理IP设置教程核对。
上线前保留可回退路径
把 Node 版本、启用方式、代理变量来源和 NO_PROXY 清单写进部署记录。升级 Node 或 Undici 时,用同一组受控端点重新验证 HTTP、HTTPS、绕过域名和错误凭据四种场景;一旦结果变化,可回退到上一锁定版本,而不是临时关闭证书校验或无限重试。
Node.js fetch环境变量代理不生效,核心排查顺序是:先确认调用栈和版本,再确认是否显式启用环境代理,随后检查 dispatcher 与 NO_PROXY,最后用受控出口对照验证。需要核对代理协议、鉴权方式、地区和会话能力时,可到悟空代理官网查看当前说明,并以实际订单与接口文档为准。

