# Axios 代理不生效：16 个原因与修复（实测）

Source: https://ipvolt.com/zh/guides/fix-axios-proxy-not-working
Markdown: https://ipvolt.com/zh/guides/fix-axios-proxy-not-working.md
Language: zh-CN

[ipvolt 首页](https://ipvolt.com/zh.md) / [指南](https://ipvolt.com/zh/guides.md) / Axios 代理不生效：16 个原因与修复（实测）

故障排查
发布于: 2026-11-11
阅读约 15 分钟
作者： ipvolt

Node.js 中 Axios 请求绕过代理或经代理失败？按症状列出 16 个原因和实测修复：1.21 中 proxy: false 绕过 proxyEnv agent、HTTP/2 与 fetch 适配器直连、1.16.1 之前不发 CONNECT、407 与密码编码、NO_PROXY 匹配、重定向、SOCKS5。

Node.js 中的 Axios 请求绕过代理，或者在经过代理时失败，原因就在下面这 16 个之中，而且大多数与 Axios 版本有关。Axios 1.21.0 和 1.21.1 在设置了 `proxy: false` 时会忽略带 `proxyEnv` 的 agent。`httpVersion: 2` 和 fetch 适配器在所有支持它们的版本上都是直连。1.16.1 之前的版本从不为 `https://` 地址建立 CONNECT 隧道。每个原因都附有我们记录的输出和我们实际运行过的修复方法。

测试环境：Node.js 24.22.2 和 26.13.0，Axios 1.12.2、1.19.0、1.20.0、1.21.0 和 1.21.1，另加 1.13.6、1.15.0、1.16.0、1.16.1 和 1.18.1 用来定位行为变化的版本，https-proxy-agent 9.1.0 和 socks-proxy-agent 10.1.0，macOS 26.5.1 arm64，2026 年 11 月 11 日。实验环境是 127.0.0.1 上一个带日志的代理和一个 HTTPS 目标。“被绕过”指目标作出了响应，而代理什么也没有记录。脚本、[结果表](/downloads/fix-axios-proxy-not-working/RESULTS.md)和全部 1290 条记录都在[实验文件夹](/downloads/fix-axios-proxy-not-working/README.md)中（英文）。第一次配置代理，请先看 [Axios 代理设置](/zh/guides/axios-proxy-setup)；本页针对的是配置好了却表现不对的情况。

## 快速检查：请求是否经过代理？

```js
import axios from 'axios';

// Use the same client and options as the code you are debugging.
const res = await axios.get('https://api.ipify.org?format=json', {
  proxy: { protocol: 'http', host: 'proxy.example', port: 8080 },
});
console.log(res.data);
```

用出问题的那段代码的选项运行一次，再完全不带代理运行一次。如果两次输出的 IP 相同，说明请求绕过了代理。`200` 什么也证明不了：本页的每一次绕过都返回了 `200`。如果能看到代理自己的日志，先看那里。在实验中，每个经过代理的 `https://` 请求都留下一行 `CONNECT`，被绕过的请求一行也没有。

## 找到你的症状

| 你看到的现象 | 前往 |
| --- | --- |
| 状态 `200`，但 IP 是你自己的，代理没有任何日志 | [请求绕过代理](#请求绕过代理且没有任何报错) |
| `400`、`socket hang up`、`wrong version number`、`ENOTFOUND undefined`，或请求一直不返回 | [经 HTTP 代理访问 HTTPS 失败](#经-http-代理访问-https-失败) |
| `Request failed with status code 407` | [407 与认证错误](#407-与认证错误) |
| 设置了 `HTTPS_PROXY` 却被忽略，或不该跳过代理的主机被跳过 | [环境变量与 NO_PROXY](#环境变量没有生效或-noproxy-匹配不对) |
| 第一个请求走代理，重定向却没有 | [重定向离开代理](#重定向离开代理) |
| `protocol mismatch`，或 SOCKS 代理无法解析主机名 | [SOCKS5 代理](#socks5-代理) |

## 请求绕过代理，且没有任何报错

### 1. proxy: false 与带 proxyEnv 的 agent 同时使用（Axios 1.21.0 及之后）

```js
import https from 'node:https';
import axios from 'axios';

const agent = new https.Agent({ proxyEnv: { https_proxy: 'http://proxy.example:8080' } });
const res = await axios.get('https://example.com/', { proxy: false, httpsAgent: agent });
console.log(res.status);
```

在 Axios 1.20.0 上，这个请求经过了实验代理。在 1.21.0 上，同一个脚本输出：

```text
200
# proxy log: (nothing)
# target log: GET /ip HTTP/1.1 direct
```

从 1.21.0 起，`proxy: false` 的含义是“直接连接”，即使 agent 自带代理设置也一样：Axios 会把 agent 换成一个不带 `proxyEnv` 的副本（[#11402](https://github.com/axios/axios/issues/11402)，2026 年 11 月 5 日关闭；改动来自 [PR #11242](https://github.com/axios/axios/pull/11242)，提交 [2498c23](https://github.com/axios/axios/commit/2498c233438eb72c9a9ee8540ded19c6ef4224fa)）。在实验中，Node 自带的开关也是同样的结果：`NODE_USE_ENV_PROXY=1` 或 `--use-env-proxy` 加上 `proxy: false`，在 1.20.0 及之前走代理，在 1.21.0 和 1.21.1 上直连。

**修复**：从使用这类 agent 的请求中去掉 `proxy: false`。#11402 的报告者确认了这一点，在实验中去掉该选项的脚本在全部十个版本上都经过了代理。agent 带有 `proxyEnv` 时，Axios 会把环境代理交给它处理（[请求配置文档](https://axios.rest/pages/advanced/request-config)）。与 `HttpsProxyAgent` 这类第三方 agent 搭配时，请保留 `proxy: false`：这一组合在所有版本上都有效（原因 5）。

### 2. httpVersion: 2

```js
import axios from 'axios';

// HTTPS_PROXY=http://proxy.example:8080 is set in the environment.
const res = await axios.get('https://example.com/', { httpVersion: 2 });
console.log(res.status);
```

在 Axios 1.21.1 上：

```text
200
# proxy log: (nothing)
# target log: GET /ip HTTP/2.0 direct
```

| Axios | `proxy` 对象 | `HTTPS_PROXY` | `proxy: false` + `HttpsProxyAgent` |
| --- | --- | --- | --- |
| 1.13.6、1.15.0、1.16.0 | `ERR_HTTP2_ERROR` | `ERR_HTTP2_ERROR` | 被绕过，无报错 |
| 1.16.1、1.18.1、1.19.0 | 被绕过，无报错 | 被绕过，无报错 | 被绕过，无报错 |
| 1.20.0、1.21.0、1.21.1 | `ERR_NOT_SUPPORT` | 被绕过，无报错 | 被绕过，无报错 |

Axios 1.12.2 不支持 HTTP/2，忽略了这个选项。安全公告 [GHSA-3pq3-5fj3-cg6v](https://github.com/axios/axios/security/advisories/GHSA-3pq3-5fj3-cg6v)（CVE-2026-101898，[GitLab 条目](https://advisories.gitlab.com/npm/axios/CVE-2026-101898/)）覆盖 1.13.0 至 1.20.0 之前的版本：HTTP/2 路径自行建立连接，丢掉了代理。实验在 1.16.1 到 1.19.0 上复现了无声的绕过。在 1.13.6、1.15.0 和 1.16.0 上，请求向代理发送了 HTTP/2 字节后以 `Protocol error` 失败，所以在这些版本上失败是看得见的，而不是无声的。

1.20.0 的修复会拒绝显式的 `proxy` 对象，报错 `HTTP/2 requests with a proxy are not supported`。它不覆盖环境变量：[PR #11141](https://github.com/axios/axios/pull/11141) 写明，当代理只来自环境变量或 agent 时，HTTP/2 仍然直连；[文档](https://axios.rest/pages/advanced/request-config)也说 HTTP/2 请求无法走代理。`NODE_USE_ENV_PROXY=1` 同样是直连。

**修复**：凡是必须走代理的请求，都去掉 `httpVersion: 2`。去掉后，同一个请求在 1.16.1 及之后的版本上以 HTTP/1.1 经过了代理。

### 3. fetch 适配器

使用 `adapter: 'fetch'` 时，`proxy` 对象、`HTTPS_PROXY` 和 `httpsAgent` 在全部十个版本、两条 Node 版本线上都被无声绕过。文档把 `proxy` 标为[仅限 Node.js](https://axios.rest/pages/advanced/request-config)，而在实验中只有默认的 HTTP 适配器会读取该选项、代理环境变量或 agent。

**修复**：去掉 `adapter: 'fetch'`，或者让 Node 为自己的 `fetch` 走代理：设置 [`NODE_USE_ENV_PROXY=1`](https://nodejs.org/api/cli.html#node_use_env_proxy1) 和 `HTTPS_PROXY` 后，fetch 适配器在 Node 24.22.2 和 26.13.0 上都经过了代理。`proxy: false` 并不能关掉它。如果报错是 `fetch failed`，请看[修复 Node.js 在代理后的 fetch failed](/zh/guides/fix-node-fetch-failed-proxy) 和 [Node.js 26 上的 invalid onError method](/zh/guides/node-26-invalid-onerror-method)。

### 4. agent 放错了选项

只把 `HttpsProxyAgent` 作为 `httpAgent` 传入，而地址是 `https://`：在所有版本上都被无声绕过。Axios 对 `http://` 请求使用 `httpAgent`，对 `https://` 请求使用 `httpsAgent`（[README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)）。

**修复**：两个选项都设置，像下文 SOCKS 示例那样。

## 经 HTTP 代理访问 HTTPS 失败

### 5. 1.16.1 之前的 Axios 不发送 CONNECT

使用 `proxy` 对象或 `HTTPS_PROXY` 时，Axios 1.12.2、1.13.6、1.15.0 和 1.16.0 没有向代理请求隧道。实验代理在一个普通请求里收到了完整的 URL：

```text
AxiosError: Request failed with status code 400
# exit code: 1
# proxy log: A GET https://target.test:<T>/ip -> 400
# target log: (nothing)
```

我们的代理用 `400` 拒绝这种请求。另一个会直接断开连接的实验代理则产生了 `socket hang up`（`ECONNRESET`），也就是 [#4531](https://github.com/axios/axios/issues/4531) 中报告的错误。该 issue 于 2022 年 3 月提交，2025 年 7 月 30 日在一次清理中关闭，当时要求报告者重新测试。[#3384](https://github.com/axios/axios/issues/3384) 于 2022 年 6 月关闭，描述的是同样的配置，但报的是某个代理特有的握手错误，我们未能复现。

[Axios 1.16.1](https://github.com/axios/axios/releases/tag/v1.16.1) 改变了这一点：按照 [PR #10858](https://github.com/axios/axios/pull/10858)，Axios 对 HTTPS 目标使用 CONNECT 隧道，而不再把请求的 URL、请求头和请求体以明文转发给代理。从 1.16.1 起，这些用例全部走了隧道。

**修复**：升级到 1.16.1 或更高版本。如果无法升级，就使用代理 agent，并关闭 Axios 自己的代理处理。这在全部十个版本上都有效，包括 1.12.2：

```js
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';

const agent = new HttpsProxyAgent('http://proxy.example:8080');
const res = await axios.get('https://example.com/', {
  proxy: false, // Axios adds no proxy handling of its own
  httpsAgent: agent, // the agent opens the CONNECT tunnel
  signal: AbortSignal.timeout(15000),
});
console.log(res.status);
```

### 6. wrong version number：代理的协议写错或漏写

```text
write EPROTO <id>:error:0A00010B:SSL routines:tls_validate_record_header:wrong version number:../deps/openssl/openssl/ssl/record/methods/tlsany_meth.c:78:
```

客户端在用 TLS 与一个只讲明文 HTTP 的代理端口通信。在所有版本上，以下写法都让实验得到了这个错误：`proxy` 对象中的 `protocol: 'https'`、`HTTPS_PROXY=https://127.0.0.1:8080`、完全不带协议的 `HTTPS_PROXY=127.0.0.1:8080`，以及 `new HttpsProxyAgent('https://…')`。在 1.16.0 及之前，不带 `protocol` 的 `proxy` 对象也以同样方式失败；从 1.16.1 起它可以正常工作。

`protocol` 和 URL 的协议描述的是到代理的连接，而不是到网站的连接：只有代理本身提供 TLS 时才使用 `https`（[README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)）。[#6198](https://github.com/axios/axios/issues/6198) 报告了使用 `HttpsProxyAgent` 时的这个错误；它在 2025 年 8 月因缺少复现步骤而关闭，而其中的配置换成 `http://` 代理地址后在我们的实验中可以正常工作。

**修复**：对普通的 HTTP 代理，写 `protocol: 'http'`，或在 URL 中写 `http://`。[经代理出现 SSL: wrong version number](/zh/guides/fix-ssl-wrong-version-number-proxy) 讲的是其他客户端中的同一个错误。

### 7. 代理写成了字符串，或协议写进了 host

- `proxy: 'http://proxy.example:8080'`（字符串）：从 1.16.1 起是 `getaddrinfo ENOTFOUND undefined`，此前是 `connect ECONNREFUSED ::1:443`。
- `proxy: { host: 'http://proxy.example', port: 8080 }`：从 1.16.1 起是 `Invalid URL`（`ERR_INVALID_URL`），此前是 `getaddrinfo ENOTFOUND http://127.0.0.1`。

两种写法都没有到达代理。2020 年关闭的 [#2072](https://github.com/axios/axios/issues/2072) 在浏览器代码中用了第二种写法，而 `proxy` 选项在浏览器中根本不起作用（[文档](https://axios.rest/pages/advanced/request-config)）；我们没有测试浏览器。

**修复**：传入一个对象，`host` 写不带协议的主机名，`port` 写数字或字符串，协议写在 `protocol` 中。

### 8. 请求一直不返回

从 Axios 1.16.1 起，使用 `proxy` 对象或 `HTTPS_PROXY` 时，如果代理在收到 `CONNECT` 后关闭连接，或者始终不应答，请求就会一直挂起：15 秒后既没有响应也没有错误，尽管设置了 `timeout: 5000`。在 1.16.1 之前，同样的用例会以 `socket hang up` 或 `timeout of 5000ms exceeded` 被拒绝。使用 `proxy: false` 加 `HttpsProxyAgent` 时，连接被关闭会以 `Proxy connection ended before receiving CONNECT response` 被拒绝，而不应答的代理在全部十个版本上都让请求一直挂起。`http://` 地址则正常被拒绝，报 `timeout of 5000ms exceeded` 或 `socket hang up`。截至 2026 年 11 月 11 日，我们没有找到关于这个问题的 Axios issue。

**修复**：给每个走代理的请求单独设置截止时间。`signal: AbortSignal.timeout(3000)` 让每个挂起的用例在 3 秒后以 `canceled`（`ERR_CANCELED`）结束。`maxRedirects: 0` 也能让 `timeout` 对内置隧道生效，[1.16.0 的发布说明](https://github.com/axios/axios/releases/tag/v1.16.0)提到过这种情况。

## 407 与认证错误

密码错误或没有密码时，所有版本返回的结果都一样，无论凭据来自 `proxy.auth`、`HTTPS_PROXY` 还是 `HttpsProxyAgent` 的 URL：`Request failed with status code 407`，其中 `error.code` 为 `ERR_BAD_REQUEST`，`error.response.status` 为 `407`。代理记录了一个请求并以 407 应答，目标什么也没有看到。SOCKS5 代理没有状态码：那里密码错误得到的是 `Socks5 Authentication failed`。

### 9. 凭据放错了位置

把代理的用户名和密码放在顶层的 `auth` 选项中，返回了 407，代理日志显示它没有收到任何凭据。顶层的 `auth` 是给网站用的；代理的凭据要放在 `proxy.auth` 中（[README](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)）。使用 `proxy.auth` 时，从 1.16.1 起代理对 `CONNECT` 完成了认证，目标始终没有看到 `Proxy-Authorization` 请求头，重定向到第二个主机时也一样。

### 10. 特殊字符的编码方式不对

实验代理期望的密码是 `p@ss/w0rd#1`：

| 密码写在哪里 | 写法 | 结果 |
| --- | --- | --- |
| `proxy.auth.password` | 原样 | 经过代理（1.16.1 及之后） |
| `proxy.auth.password` | 百分号编码 | 407：代理收到的是 `p%40ss%2Fw0rd%231` |
| `HTTPS_PROXY` 的 URL | 原样 | `getaddrinfo ENOTFOUND ss` |
| `HTTPS_PROXY` 的 URL | 百分号编码 | 407：代理收到的是 `p%40ss%2Fw0rd%231` |
| `HttpsProxyAgent` 的 URL | 百分号编码 | 经过代理（所有版本） |

原样粘贴时，`@` 提前结束了凭据部分，`ss` 成了主机名。使用百分号编码时，URL 可以解析，但 Axios 把其中的用户名和密码原样取出，不做解码（[1.21.1 的 http.js](https://github.com/axios/axios/blob/v1.21.1/lib/adapters/http.js)）。因此在测试过的版本上，含保留字符的密码根本无法通过 `HTTPS_PROXY` 传递。

**修复**：在 `proxy.auth` 中不编码地传入，或者在 agent 的 URL 中使用百分号编码。下面两个请求在 1.19.0 到 1.21.1 上都经过了代理：

```js
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';

const user = process.env.PROXY_USER;
const pass = process.env.PROXY_PASS;

// In the proxy object: the raw password, not percent-encoded.
const a = await axios.get('https://example.com/', {
  proxy: { protocol: 'http', host: 'proxy.example', port: 8080, auth: { username: user, password: pass } },
});

// In a proxy URL for an agent: percent-encode both parts.
const url = `http://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@proxy.example:8080`;
const b = await axios.get('https://example.com/', { proxy: false, httpsAgent: new HttpsProxyAgent(url) });
console.log(a.status, b.status);
```

如果凭据正确仍然出现 407，例如由于 IP 白名单或用户名格式，请看[修复代理错误 407](/zh/guides/fix-proxy-error-407)。

## 环境变量没有生效，或 NO_PROXY 匹配不对

在实验中，Axios 在全部十个版本上读取的是：`https://` 地址读 `HTTPS_PROXY` 或 `https_proxy`，`http://` 地址读 `HTTP_PROXY` 或 `http_proxy`，缺少对应变量时读 `ALL_PROXY` 或 `all_proxy`。大小写两种写法都设置时，小写的优先。变量在发出请求时读取，所以在请求前用代码给 `process.env.HTTPS_PROXY` 赋值是有效的。`proxy` 对象的优先级高于这些变量和 `NO_PROXY`。在 1.16.1 之前，变量的读取方式相同，但 `https://` 请求随后会像原因 5 那样失败。

### 11. 变量与 URL 的协议不匹配

只设置 `HTTP_PROXY` 时，`https://` 请求在所有版本上都是直连，没有任何报错。只设置 `HTTPS_PROXY` 时，`http://` 请求也是如此。

**修复**：两个都设置，通常指向同一个 `http://` 代理地址。[代理环境变量](/zh/guides/proxy-environment-variables)比较了其他客户端读取它们的方式。

### 12. 环境中的代理覆盖了你的 agent

设置了 `HTTPS_PROXY` 时，作为 `httpsAgent` 传入、且没有 `proxy: false` 的 `HttpsProxyAgent` 或 `SocksProxyAgent` 会被忽略：从 1.16.1 起，请求走的是环境变量中的代理，而不是 agent 的代理。与 agent 同时存在的 `proxy` 对象也以同样的方式胜出。只要 CI 运行器或容器设置了 `HTTPS_PROXY`，你的流量就可能走另一个代理，而不是代码中写的那个。

**修复**：凡是使用第三方代理 agent 的请求，都加上 `proxy: false`。加上之后，无论环境里有什么，请求在全部十个版本上都走了 agent 的代理。

### 13. NO_PROXY 在不同版本上匹配结果不同

设置了代理变量，URL 的主机为 `target.test` 时：

| `NO_PROXY` | 路由 | 版本 |
| --- | --- | --- |
| `target.test`、`TARGET.TEST`、`.test`、`*.test`、`*`、带 URL 端口的 `target.test:PORT` | 直连 | 全部 |
| `other.test target.test` 或 `other.test, target.test` | 直连 | 全部 |
| `.target.test`、`test`、`get.test`、`target.test:9999`、`https://target.test` | 代理 | 全部 |
| `target.test`，而 URL 写的是带结尾点号的 `target.test.` | 1.12.2 和 1.13.6 走代理，1.15.0 起直连 | 在 1.15.0 中修复 |
| `127.0.0.0/8`，URL 主机为 `127.0.0.1` | 1.19.0 及之前走代理，1.20.0 起直连 | 在 1.20.0 中修复 |
| `localhost`，URL 主机为 `127.0.0.1` | 1.15.0 及之前走代理，1.16.0 起直连 | 在 1.16.0 中变更 |

结尾点号那一行对应 [GHSA-3p68-rc4w-qgx5](https://github.com/axios/axios/security/advisories/GHSA-3p68-rc4w-qgx5)，在 1.15.0 中修复。CIDR 那一行对应 [GHSA-44g4-m2mj-wpvx](https://github.com/axios/axios/security/advisories/GHSA-44g4-m2mj-wpvx)（CVE-2026-101899），在 1.20.0 中修复；公告列出的受影响版本是 1.15.0 及之后，而在实验中 1.12.2 和 1.13.6 同样忽略了 CIDR 条目。未设置 `NO_PROXY` 时，发往 `localhost` 和 `127.0.0.1` 的请求在所有版本上都走了代理。[NO_PROXY 匹配规则实测](/zh/blog/no-proxy-matching-tested)中有针对其他客户端的同一张矩阵。

## 重定向离开代理

### 14. 重定向改变了协议，或跳到了 NO_PROXY 中的主机

实验目标以 `302` 跳转到第二个主机。

- **从 `http://` 到 `https://`，只设置了 `HTTP_PROXY`**：第一跳走代理，第二跳直连，所有版本都是如此。使用 `proxy: false` 且只设置 `httpAgent` 时也一样。两个 agent 都设置时，或从 1.16.1 起两个变量都设置时，两跳都走代理。
- **从 `https://` 到另一个主机的 `https://`**：使用 `proxy` 对象、`HTTPS_PROXY` 或 agent 时，从 1.16.1 起两跳都走代理。启用代理认证时，两个 `CONNECT` 请求都带有凭据。
- **重定向到 `NO_PROXY` 中列出的主机**：在 1.21.0 和 1.21.1 上，第二跳直连。在 1.16.1 到 1.20.0 上，它仍然走代理。使用显式的 `proxy` 对象时，从 1.16.1 起两跳都走代理。

**修复**：两个变量或两个 agent 都设置。如果重定向绝不能离开代理，就使用 `proxy` 对象，或一对 agent 加 `proxy: false`，并且不要把那个主机写进 `NO_PROXY`。

## SOCKS5 代理

### 15. 在 proxy 选项或 HTTPS_PROXY 中使用 socks5://

Axios 没有 SOCKS 客户端。`proxy: { protocol: 'socks5', … }` 和 `HTTPS_PROXY=socks5://…` 在 1.16.0 及之前以 `protocol mismatch`（`ERR_ASSERTION`）失败。从 1.16.1 起，Axios 向 SOCKS 端口发送了一行 HTTP `CONNECT`，实验的 SOCKS 服务器关闭了连接，请求一直不返回（原因 8）。

**修复**：在两个 agent 选项中都使用 SOCKS agent，并加上 `proxy: false`（原因 12）。这样请求在全部十个版本上都经过了实验的 SOCKS5 代理：

```js
import axios from 'axios';
import { SocksProxyAgent } from 'socks-proxy-agent';

// socks5h: the proxy resolves the hostname. socks5: this machine does.
const agent = new SocksProxyAgent('socks5h://proxy.example:1080');
const res = await axios.get('https://example.com/', {
  proxy: false,
  httpAgent: agent,
  httpsAgent: agent,
  signal: AbortSignal.timeout(15000),
});
console.log(res.status);
```

### 16. 该用 socks5h 却用了 socks5

使用 `socks5://` 时，实验的 SOCKS 服务器收到的是 IP 地址：客户端自己解析了主机名。使用 `socks5h://` 时，它收到的是主机名（[socks-proxy-agent README](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent)）。对于只有代理才能解析的名称，`socks5://` 以 `getaddrinfo ENOTFOUND proxy-only.test` 失败，而 `socks5h://` 可以正常工作。[SOCKS5 与 SOCKS5h](/zh/blog/socks5-vs-socks5h) 说明了本地 DNS 查询还会泄露什么。

## 每种需求的可靠配置

三种配置在 Axios 1.19.0、1.20.0、1.21.0 和 1.21.1 上、两条 Node 版本线上都经过了实验代理。在 1.12.2 上只有第三种有效。

**在代码中固定一个代理**（Axios 1.16.1 或更高版本）：

```js
import axios from 'axios';

const client = axios.create({
  proxy: {
    protocol: 'http', // how to reach the proxy, not the site
    host: 'proxy.example',
    port: 8080,
    auth: { username: process.env.PROXY_USER, password: process.env.PROXY_PASS },
  },
});

const res = await client.get('https://example.com/', { signal: AbortSignal.timeout(15000) });
console.log(res.status);
```

**来自环境变量的公司代理**（Axios 1.16.1 或更高版本）。在代码之外设置变量：

```sh
export HTTPS_PROXY=http://proxy.example:8080
export HTTP_PROXY=http://proxy.example:8080
export NO_PROXY=localhost,127.0.0.1
```

```js
import axios from 'axios';

// Started with HTTPS_PROXY, HTTP_PROXY and NO_PROXY in the environment.
// No proxy option, no agent, no httpVersion, default adapter.
const res = await axios.get('https://example.com/', { signal: AbortSignal.timeout(15000) });
console.log(res.status);
```

**每个请求使用不同的代理**（所有测试过的版本）：

```js
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';

const agents = new Map();
const agentFor = (proxyUrl) => {
  if (!agents.has(proxyUrl)) agents.set(proxyUrl, new HttpsProxyAgent(proxyUrl));
  return agents.get(proxyUrl);
};

const viaProxy = (url, proxyUrl) =>
  axios.get(url, { proxy: false, httpsAgent: agentFor(proxyUrl), signal: AbortSignal.timeout(15000) });

const first = await viaProxy('https://example.com/', 'http://proxy-a.example:8080');
const second = await viaProxy('https://example.com/', 'http://proxy-b.example:8080');
console.log(first.status, second.status);
```

在实验中，两个请求分别从两个不同的代理发出。对于 `http://` 地址，再把 `http-proxy-agent` 的 `HttpProxyAgent` 作为 `httpAgent` 传入。

## 给测试加一道防护

上面的大多数原因都返回 `200`，所以当一次升级或一个新选项开始绕过代理时，普通的测试套件仍然全部通过。下面这个测试会启动一个替身代理，它记录收到的内容并予以拒绝，然后通过你的应用构建的客户端发送一个请求：

```js
import assert from 'node:assert/strict';
import { once } from 'node:events';
import http from 'node:http';
import { test } from 'node:test';
import { createClient } from './client.mjs';

test('the HTTP client sends requests through the proxy', async () => {
  const seen = [];
  // A stand-in proxy: it records what arrives and refuses it, so nothing leaves the machine.
  const proxy = http.createServer((req, res) => {
    seen.push(`${req.method} ${req.url}`);
    res.writeHead(503).end();
  });
  proxy.on('connect', (req, socket) => {
    seen.push(`CONNECT ${req.url}`);
    socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n');
  });
  proxy.listen(0, '127.0.0.1');
  await once(proxy, 'listening');

  const client = createClient(`http://127.0.0.1:${proxy.address().port}`);
  // .invalid never resolves, so a request that skips the proxy cannot reach a real site.
  await client.get('https://guard.invalid/', { signal: AbortSignal.timeout(5000) }).catch(() => {});
  proxy.close();

  assert.deepEqual(seen, ['CONNECT guard.invalid:443']);
});
```

`createClient(proxyUrl)` 是你自己的工厂函数。使用上面“每个请求使用不同的代理”的客户端时，`node --test` 在五个主要版本上全部通过。给同一个客户端加上 `adapter: 'fetch'` 之后，它失败了：

```text
not ok 1 - the HTTP client sends requests through the proxy
    Expected values to be strictly deep-equal:
    + actual - expected
    + []
    - [
    -   'CONNECT guard.invalid:443'
    - ]
# tests 1
# pass 0
# fail 1
# exit code: 1
```

## 该用和该避开的版本

- **使用 1.21.1**，即测试当天的最新版本，或至少使用 1.20.0。升级后检查两件事：`proxy: false` 与带 `proxyEnv` 的 agent 同时使用（原因 1），以及重定向到 `NO_PROXY` 中的主机（原因 14）。
- **1.16.1 之前**：经 HTTP 代理访问 `https://` 地址时没有 CONNECT 隧道（原因 5）。请使用 agent 方案或升级。
- **1.13.0 到 1.19.0 且使用 `httpVersion: 2`**：在 GHSA-3pq3-5fj3-cg6v 的范围内。在 1.20.0 及之后，HTTP/2 仍然忽略 `HTTPS_PROXY`（原因 2）。
- **1.15.0 之前和 1.20.0 之前**：`NO_PROXY` 分别无法匹配带结尾点号的主机和 CIDR 网段（原因 13）。
- **Node.js**：24.22.2 和 26.13.0 对每个用例的路由结果相同。唯一的区别：通过 fetch 适配器时，Node 26 与实验目标协商了 HTTP/2，而 Node 24 使用 HTTP/1.1。

## 常见问题

### 为什么 Axios 忽略 HTTPS_PROXY？

在实验中有六种原因：请求设置了 `proxy: false`、`httpVersion: 2`、`adapter: 'fetch'`、优先级更高的 `proxy` 对象、命中了 `NO_PROXY`，或者地址是 `http://`，这时读取的是 `HTTP_PROXY`。

### 使用 Axios 还需要 https-proxy-agent 吗？

在 Axios 1.16.1 或更高版本上使用单个 HTTP 代理时不需要：`proxy` 对象和 `HTTPS_PROXY` 会自行建立隧道。旧版本需要它，而且它是为每个请求使用不同代理的最简单方式。

### Axios 支持 SOCKS5 代理吗？

不能通过 `proxy` 或 `HTTPS_PROXY` 使用。请把 `SocksProxyAgent` 作为 `httpAgent` 和 `httpsAgent` 传入，并加上 `proxy: false`。

### 为什么设置了 timeout，Axios 请求经过代理时还是会挂起？

在测试过的版本上，`timeout` 不覆盖代理不应答 `CONNECT` 的情况（原因 8）。请加上 `signal: AbortSignal.timeout(ms)`。

### Axios 的 proxy 选项在浏览器中有效吗？

无效。文档把 `proxy` 标为仅限 Node.js；浏览器使用操作系统或浏览器自身的代理。

## 相关指南

- [Axios 代理设置](/zh/guides/axios-proxy-setup)是配置页：一次显式的代理检查，以及由哪一层决定路由。
- [代理环境变量](/zh/guides/proxy-environment-variables)比较了 curl、Requests 和 Node 读取它们的方式。
- [修复代理错误 407](/zh/guides/fix-proxy-error-407) 讲的是与编码无关的 407。
- [fetch failed：Node.js 26 上的 invalid onError method](/zh/guides/node-26-invalid-onerror-method) 是 undici 代理 agent 在 Node 26 上的故障。
- [修复 Node.js 在代理后的 TypeError: fetch failed](/zh/guides/fix-node-fetch-failed-proxy) 讲的是使用 `fetch` 时如何读错误链。
- [NO_PROXY 匹配规则实测](/zh/blog/no-proxy-matching-tested)中有其他客户端的匹配规则。

**用真实 IP 测试这个修复。** ipvolt 出售[住宅代理](/residential-proxies)，每 GB $2.20 起，以及专用的[移动代理](/mobile-proxies)，每天 $9 起。把代理填入上面的配置，然后运行快速检查。[立即检查代理](/tools/proxy-checker)。

## 参考来源与延伸阅读

- [axios/axios#11402: axios@1.21.0 breaks custom https.Agent with proxyEnv enabled](https://github.com/axios/axios/issues/11402)
- [axios/axios#11242: align request handling across runtimes (direct agents for proxy: false)](https://github.com/axios/axios/pull/11242)
- [axios/axios commit 2498c23](https://github.com/axios/axios/commit/2498c233438eb72c9a9ee8540ded19c6ef4224fa)
- [GHSA-3pq3-5fj3-cg6v (CVE-2026-101898): HTTP/2 adapter bypasses configured DNS lookup and proxy controls](https://github.com/axios/axios/security/advisories/GHSA-3pq3-5fj3-cg6v)
- [GitLab advisory database: CVE-2026-101898](https://advisories.gitlab.com/npm/axios/CVE-2026-101898/)
- [axios/axios#11141: HTTP/2 proxy handling and CIDR matching for NO_PROXY](https://github.com/axios/axios/pull/11141)
- [GHSA-3p68-rc4w-qgx5: NO_PROXY hostname normalization bypass](https://github.com/axios/axios/security/advisories/GHSA-3p68-rc4w-qgx5)
- [GHSA-44g4-m2mj-wpvx (CVE-2026-101899): CIDR-form NO_PROXY entries are ignored](https://github.com/axios/axios/security/advisories/GHSA-44g4-m2mj-wpvx)
- [axios/axios#4531: Proxy support does not work properly with CONNECT on https requests](https://github.com/axios/axios/issues/4531)
- [axios/axios#3384: HTTPS over HTTP Proxy Fails](https://github.com/axios/axios/issues/3384)
- [axios/axios#2072: Axios proxy is not working](https://github.com/axios/axios/issues/2072)
- [axios/axios#6198: https proxy agent not working as expected](https://github.com/axios/axios/issues/6198)
- [axios/axios#10858: CONNECT tunnelling for HTTPS targets](https://github.com/axios/axios/pull/10858)
- [Axios 1.16.0 release notes](https://github.com/axios/axios/releases/tag/v1.16.0)
- [Axios 1.16.1 release notes](https://github.com/axios/axios/releases/tag/v1.16.1)
- [Axios 1.20.0 release notes](https://github.com/axios/axios/releases/tag/v1.20.0)
- [Axios 1.21.0 release notes](https://github.com/axios/axios/releases/tag/v1.21.0)
- [Axios 1.21.1 release notes](https://github.com/axios/axios/releases/tag/v1.21.1)
- [Axios docs: request config (proxy, httpAgent, httpsAgent, environment variables)](https://axios.rest/pages/advanced/request-config)
- [Axios 1.21.1 README: request config](https://github.com/axios/axios/blob/v1.21.1/README.md#request-config)
- [Axios 1.21.1: HTTP adapter source](https://github.com/axios/axios/blob/v1.21.1/lib/adapters/http.js)
- [Node.js HTTP: built-in proxy support and the Agent proxyEnv option](https://nodejs.org/api/http.html#built-in-proxy-support)
- [Node.js CLI: NODE_USE_ENV_PROXY=1](https://nodejs.org/api/cli.html#node_use_env_proxy1)
- [Node.js CLI: --use-env-proxy](https://nodejs.org/api/cli.html#--use-env-proxy)
- [socks-proxy-agent README](https://github.com/TooTallNate/proxy-agents/tree/main/packages/socks-proxy-agent)

## 相关指南

- [Axios 代理设置：路由、认证与 NO_PROXY](https://ipvolt.com/zh/guides/axios-proxy-setup.md)
- [代理环境变量：HTTP_PROXY 与 NO_PROXY](https://ipvolt.com/zh/guides/proxy-environment-variables.md)
- [不靠猜测修复代理错误 407](https://ipvolt.com/zh/guides/fix-proxy-error-407.md)

## 关于 ipvolt

示例使用通用的代理设置，并附上原始技术文档链接。具体产品的行为请向你的服务商确认。ipvolt 销售移动代理和住宅代理，住宅代理每 GB $2.20 起。

[阅读英文原文](https://ipvolt.com/guides/fix-axios-proxy-not-working.md)

## 接入你的第一个代理。

移动代理每天 $9 起。住宅代理每 GB $2.20 起。

[购买移动代理](https://ipvolt.com/dashboard/mobile)

[购买住宅代理](https://ipvolt.com/dashboard/residential)

