跳到正文

Node fetch、axios 使用代理:5 个坑

给 Node.js 的 fetch 和 axios 配代理的四种办法,以及让它们悄悄直连的几个坑。

为什么 fetch 还是显示你自己的 IP

只设 HTTP_PROXY 不够:Node 文档写明,代理支持默认关闭,要设 NODE_USE_ENV_PROXY=1 或加 --use-env-proxy,而且变量是进程启动时读的。我们测试时,Node 24.14.0 下只设 HTTP_PROXY、不加开关,请求直接到了测试页。

还有三个坑。文件开头导入 undici 包,可能会换掉全局 dispatcher:导入 undici 8.12.4 后,即使开了 NODE_USE_ENV_PROXY=1,fetch 也直连,而 undici 7.30.2 没有这个现象。用已安装 undici 创建的 dispatcher,在两边版本不同时可能被内置 fetch 拒绝(我们遇到 UND_ERR_INVALID_ARG)。axios 完全不用 Node 的开关:它自己读同样的变量,一旦传了 proxy 选项或 agent,就以后者为准。

第二个坑的办法是:fetch 和 dispatcher 用同一个包里的,或者用 setGlobalDispatcher() 全局注册。

给 fetch 和 axios 配代理的四种方式

给 fetch 和 axios 配代理的四种方式
项目覆盖范围SOCKS5先检查
NODE_USE_ENV_PROXY=1(或 --use-env-proxy)内置 fetch 和 http/https 请求,读 HTTP_PROXY、HTTPS_PROXY、NO_PROXY不支持:文档只写了 http:// 和 https:// 代理地址Node 24,或 22.21 及以上;要在进程启动前设好,不能运行中再设
undici EnvHttpProxyAgent + setGlobalDispatcher注册之后所有 fetch(),读同样的变量变量方式不支持尽早注册一次;fetch 与 agent 的版本要一致
undici ProxyAgent 作为 dispatcher单次调用;设成全局则所有调用支持:socks: 开头的地址(测试时有“实验性”警告)fetch 用 undici 里的;HTTP 代理地址里的账号密码要做百分号编码
axios 的 proxy 选项或环境变量只管 axios 请求;HTTP 代理,https:// 目标走 CONNECT 隧道不支持,文档没写proxy: false 会同时关掉选项和环境变量
axios + socks-proxy-agentaxios 请求走 SOCKS5 代理支持,agent 要同时给 httpAgent 和 httpsAgent设 proxy: false,别让 axios 再加一层

来源:Node.js、undici、axios 文档,以及我们 2026 年 11 月 14 日的本地测试(Node.js 24.14.0、axios 1.21.1)。版本号即测试时所用版本。

本地代理上的实测结果

我们在一个要登录、并记录每个请求的本地代理上跑了每种写法。不加开关时,内置 fetch 无视 HTTP_PROXY;设 NODE_USE_ENV_PROXY=1 后,请求带着登录到了代理;EnvHttpProxyAgent 用 setGlobalDispatcher 注册后可用,undici 的 ProxyAgent 配 undici 自己的 fetch 也可用。axios 通过 proxy 选项和环境变量都可用,配上 SocksProxyAgent 连本地 SOCKS5 代理也可用。

测试页是纯 HTTP;至于 https:// 页面,文档说 undici 和 axios 都会开 CONNECT 隧道。这些结论会随版本变化,请在自己的版本上做同样的检查。

内置支持:启动 Node 时带上变量

# Node.js 24 (or 22.21 and newer): switch the built-in support on at start-up
NODE_USE_ENV_PROXY=1 \
HTTPS_PROXY="http://LOGIN:PASSWORD@HOST:2222" \
NO_PROXY="localhost,127.0.0.1" \
node app.js

# the same thing as a flag
HTTPS_PROXY="http://LOGIN:PASSWORD@HOST:2222" node --use-env-proxy app.js

仅为示例:把 LOGIN、PASSWORD、HOST 换成「我的资产」里的值;账号密码里的特殊字符要做百分号编码。

用 undici 的 fetch:单次调用或整个进程

// npm i undici
import { fetch, ProxyAgent, EnvHttpProxyAgent, setGlobalDispatcher } from 'undici'

// A) one dispatcher for one call. Use fetch from the same undici package.
const login = encodeURIComponent('LOGIN')
const pass = encodeURIComponent('PASSWORD')
const agent = new ProxyAgent(`http://${login}:${pass}@HOST:2222`)
const res = await fetch('https://ipinfo.io/json', { dispatcher: agent })
console.log(await res.json())

// B) every fetch() in the process, driven by HTTPS_PROXY / NO_PROXY
// (the agent does nothing until it is registered)
setGlobalDispatcher(new EnvHttpProxyAgent())

2026 年 11 月 14 日在需要登录的本地 HTTP 代理上验证,测试页为纯 HTTP,undici 为 8.12.4 与 7.30.2。请把占位符换成自己的值。

axios:HTTP 用 proxy 选项,SOCKS5 用 agent

// npm i axios socks-proxy-agent
import axios from 'axios'
import { SocksProxyAgent } from 'socks-proxy-agent'

// HTTP proxy: axios' own proxy option
const viaHttp = await axios.get('https://ipinfo.io/json', {
  proxy: { protocol: 'http', host: 'HOST', port: 2222, auth: { username: 'LOGIN', password: 'PASSWORD' } },
})
console.log(viaHttp.data)

// SOCKS5 proxy: hand axios an agent and turn its own proxy handling off
const agent = new SocksProxyAgent(
  `socks5h://${encodeURIComponent('LOGIN')}:${encodeURIComponent('PASSWORD')}@HOST:3333`
)
const viaSocks = await axios.get('https://ipinfo.io/json', { proxy: false, httpAgent: agent, httpsAgent: agent })
console.log(viaSocks.data)

两种写法都在 2026 年 11 月 14 日用带登录的本地代理验证过(HTTP 页面)。请换上自己的值,端口要和所买协议一致。

带账号密码的 SOCKS5:两个细节

socks-proxy-agent 会先把百分号编码的账号密码解码再发送:测试里代理收到的是原始用户名和密码,用 socks5h 时收到的是域名而不是 IP。undici 的 ProxyAgent 配 socks5: 地址时没有解码:代理收到的 %40、%3A 是原样字符。密码含特殊字符时,请用 socks-proxy-agent,或者换一个不含特殊字符的密码。

两个库都要求代理在 SOCKS5 端口上说 SOCKS5。Proxy302 的 SOCKS5 端口是 3333,且凭据要是按 SOCKS5 生成的;HTTP 用 2222。

症状与处理

脚本打印出的是你自己的 IP

检查 node 启动前设了 NODE_USE_ENV_PROXY=1 吗,Node 是 24 或 22.21 以上吗?文件里导入了 undici 吗?axios 里设了 proxy: false 吗?

处理 带变量启动,打印 process.version 和 process.versions.undici,再请求 https://ipinfo.io/json;用和你的库匹配的 dispatcher 或 agent。

停止条件 全局注册 dispatcher 后出口仍是你自己的 IP,就别再改代码,改用 curl 测代理本身。

fetch failed,错误码 UND_ERR_INVALID_ARG

检查 dispatcher 是不是来自已安装的 undici,而 fetch 用的是内置的?

处理 fetch 也从 undici 导入,或用 setGlobalDispatcher() 全局注册。

407 或 Proxy Authentication Required

检查 URL 里的账号密码做百分号编码了吗?是这条资产自己的账号密码吗?

处理 重新从「我的资产」复制 host、port、username、password,密码用 encodeURIComponent 编码。

SOCKS5 地址报 ECONNRESET 或 socket hang up

检查 端口是 3333 吗?凭据是按 SOCKS5 生成的吗?

处理 按 SOCKS5 重新生成或购买,或者把代码改成 HTTP 端口 2222 和 http:// 代理地址。

Node.js 脚本该选哪种 Proxy302 产品

服务器、测试和不登录账号的脚本,可以按 IP 租机房 IP:1 天 US$0.25,30 天 US$3.99,购买时选 HTTP(端口 2222)或 SOCKS5(端口 3333),一次最多买 100 个。机房 IP 能被识别为机房地址,所以涉及账号、店铺、广告账户的工作,请选静态 ISP IP,每天 US$0.50 起。

没有免费试用,最小的购买是 1 个 IP 用 1 天。

用 Proxy302 怎么做:步骤

  1. 第 1 步

    打开机房页面,选国家、租期和协议(fetch 与 axios 的 proxy 选项选 HTTP,agent 方案选 SOCKS5),确认费用后用钱包支付。

  2. 第 2 步

    打开「我的资产」,复制 host、port、username、password。

  3. 第 3 步

    填进你选的写法里,或者填进内置开关用的 HTTPS_PROXY。

  4. 第 4 步

    请求 https://ipinfo.io/json,对比打印出的 IP 和你自己的 IP。

    预期结果 显示代理的 IP,而不是你自己的。

常见问题

Node.js 的 fetch 会用 HTTP_PROXY 吗?

默认不会。内置支持默认关闭,要在启动时设 NODE_USE_ENV_PROXY=1 或加 --use-env-proxy,Node 要在 24 或 22.21 以上。

axios 怎么用 SOCKS5 代理?

创建 SocksProxyAgent,同时传给 httpAgent 和 httpsAgent,并设 proxy: false。axios 文档里没有自带 SOCKS 支持。

内置 fetch 为什么不认我的 undici ProxyAgent?

两者可能来自不同版本的 undici。请用 undici 包里的 fetch,或把 dispatcher 设成全局。

HTTP_PROXY 和 http_proxy 哪个优先?

Node 和 undici 的文档都写明:两者同时设置时,小写形式优先。

undici 支持 SOCKS5 吗?

文档里写了通过 socks5: 地址支持 SOCKS5。我们测试可用,并会打印“实验性”警告。

参考资料

9
  1. Node.js 文档:NODE_USE_ENV_PROXY 与 --use-env-proxy

    官方文档 · 确认日期:

    2026 年 11 月 14 日读命令行选项页:NODE_USE_ENV_PROXY=1 自 v24.0.0 和 v22.21.0 加入,稳定性 1.1(开发中);开启后 Node 在启动时解析 HTTP_PROXY、HTTPS_PROXY、NO_PROXY,并让请求走代理。

  2. Node.js 文档:内置代理支持(http)

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:变量设为 1 时全局 agent 以 proxyEnv: process.env 创建;小写变量优先于大写;代理地址可写 http:// 或 https://,带登录写成 user:pass@host:port;NO_PROXY 的写法;http.setGlobalProxyFromEnv() 可在代码里为 fetch() 和 http.request() 打开。

  3. Node.js 文档:fetch 与自定义 dispatcher(globals)

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:fetch 基于 undici;process.versions.undici 可看内置版本;fetch 接受 dispatcher 选项;装了 undici 包后调用 setGlobalDispatcher() 会同时影响 undici 和 Node.js。

  4. undici 文档:EnvHttpProxyAgent

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:读取 http_proxy、https_proxy、no_proxy(及大写形式,两者同时存在时小写优先);setGlobalDispatcher(new EnvHttpProxyAgent()) 后 fetch 才会使用;只创建对象不会有任何效果。

  5. undici 文档:ProxyAgent

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:支持 HTTP、HTTPS 和 SOCKS5 代理;socks5: 地址交给 Socks5ProxyAgent;HTTP 代理地址里的账号密码会先做 URL 解码;HTTPS 目标走 CONNECT 隧道。

  6. axios README:请求配置(proxy)

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:proxy 对象(protocol、host、port、auth);设为 false 会关闭代理并忽略环境变量;认 http_proxy、https_proxy、no_proxy;https:// 目标会开 CONNECT 隧道并在隧道请求上发 Proxy-Authorization;传入自己的 agent 时由 agent 负责隧道。文档没有提 SOCKS。

  7. socks-proxy-agent README

    官方文档 · 确认日期:

    2026 年 11 月 14 日读:SocksProxyAgent 是具名导出,作为 agent 选项传给 https.get;README 没写 axios 用法,也没写 socks5h,这两处以我们自己的测试为准。

  8. 本地测试,2026-11-14

    本地示例 · 确认日期:

    2026 年 11 月 14 日在 macOS 上用 Node.js 24.14.0(内置 undici 7.21.0)、axios 1.21.1、undici 8.12.4 和 7.30.2、socks-proxy-agent 测试:一个需要登录的本地 HTTP 代理、一个带登录的本地 SOCKS5 代理和一个纯 HTTP 测试页,在代理端记录每个请求。

    测试页是纯 HTTP;HTTPS 隧道部分来自文档。版本更新很快,请在自己的版本上复测。

  9. Proxy302 产品信息与价格表

    产品观察 · 确认日期:

    网站产品信息表(2026 年 11 月 10 日核对):协议与端口、美元价格(1 PTC = US$1)、租期、数量上限、无免费试用。

准备好试试了吗?

注册账号、充值一次,就能选动态住宅、静态 ISP 或数据中心 IP,几分钟配进你的浏览器。