現在在 Stack Overflow 的某個角落,應該還有人深信 Axios 會在 HTTPS proxy 上「悄悄失效」。這種說法在 Node.js proxy 教學裡被一再提起,但其實跟本指南實測的最新版本不相符。我架了一套本機測試環境,把真實的 HTTP 與 HTTPS 來源站點放在兩個 proxy 後面,結果 Axios 1.19.0 透過正確的 CONNECT 請求把 HTTPS 請求成功穿隧過去,並沒有繞過 proxy。
這不代表大家抱怨的問題都是空穴來風。舊版 Axios 確實曾經有真實 bug(可參考 issue #3384 與 issue #4531 的紀錄),而較新的 Node 版本也多了一條環境變數 proxy 路徑,需要仔細設定。本指南會帶你了解目前 Axios 1.19.0 到底哪些做法真的有效、如何把 proxy 接到請求中、如何用 interceptor 做輪替(幾乎沒什麼教學會講這招),以及當情況出錯時,從錯誤到修正的完整對照表。
什麼是 Axios Proxy?為什麼在 Node.js 裡這麼重要?
在 Axios 的脈絡中,proxy 就是位在你的 Node 程序與目標網站之間的中介伺服器。你的請求會先送到 proxy,再由 proxy 轉發出去,而目標網站看到的是 proxy 的 IP,而不是你的。原理就這麼單純。
開發者會用它,通常是為了幾個原因:抓取會依 IP 限流或封鎖的網站、測試應用在不同地理位置下的表現、把流量導經公司出口節點,或只是不要讓自己伺服器的 IP 出現在目標站的存取紀錄裡。Axios 的官方 request config 提供了內建的 proxy 選項,包含 host、port、protocol 和 auth 欄位——這個功能已經存在很多年了,也是每一篇教學(包括這篇)最先會示範的東西。
但有一個常被忽略的重點:proxy 選項在請求 HTTP 與 HTTPS 目標時的行為並不相同,而且還會受到你使用的 Axios 版本影響。也正因為這個差異,才有這篇指南的存在。
設定 Node.js 與 Axios(快速起步)
如果你已經有現成專案,可以跳過這段。沒有的話,大概兩分鐘就能搞定。
mkdir axios-proxy-demo && cd axios-proxy-demo
npm init -y
npm install axios
如果你想用 ESM import,記得在 package.json 加上 "type": "module"(我會這樣做,畢竟現在還用 CommonJS require() 來示範 proxy,總覺得有點過時)。目前 Node LTS 是 v24.18.0,不過我實際測試是用 v22.22.3,這樣結果才不會受最新 runtime 的細節影響。
把下面內容放進 app.js,然後執行 node app.js:
import axios from 'axios';
const res = await axios.get('https://httpbin.org/ip');
console.log(res.data);
你應該會看到回應裡顯示的是你的真實 IP。這就是基準值——等 proxy 正常運作後,同一個請求應該會回傳 proxy 的 IP。
在啟用 proxy 之前,先把這個回應記下來;之後你就有一個清楚的基準,可以拿來和下一步的代理請求做比較。
Axios 到底支援 HTTPS Proxy 嗎?先把事情說清楚
簡短答案:支援,而且在目前穩定版中確實可用。Axios 1.19.0 文件說明了當 HTTPS 目標位於 HTTP proxy 後方時,會使用 CONNECT 穿隧。npm downloads API 顯示 2026 年 7 月 31 日到 8 月 6 日之間,Axios 共被下載 117,890,039 次,這雖然是有時間性的數字,但也能反映這套函式庫的使用範圍有多廣。當你透過 proxy 存取 HTTPS URL 時,目前的 Axios 會先送出 CONNECT 請求建立通道,而 TLS 握手則會直接在你與真實來源站之間完成。我直接做過測試:本機 HTTP proxy、本機 HTTPS 來源站、使用自簽憑證,而 proxy 上的 CONNECT 計數器也確實如預期增加。
那為什麼「Axios HTTPS proxy 壞掉了」幾乎在每個論壇討論串裡都會出現?原因有幾個,而且都是真的:
- 舊版 Axios。 大家常貼的 GitHub issue 往往是很多年前的內容,描述的是特定版本或特定設定下的行為,不能直接拿來概括現在的 Axios。
- Proxy 伺服器不支援 CONNECT。 在這種情況下,隧道會失敗,Axios 也應該回報錯誤;在判斷是不是 IP 被繞過之前,應該先確認實際路徑與錯誤內容。
- 把
proxy設定誤解成別的東西。proxy選項是 forward proxy 指示,並不是一個「不管什麼情況都把所有流量導到這個 agent」的通用開關。
Chromium 在 2023 年指出,主要平台上超過 90% 的 Chrome 導航使用 HTTPS。這是一個偏舊的 Chrome 指標,不是整個網路的即時統計,但它也說明了為什麼 HTTPS 目標的行為必須放在這篇教學的核心。如果你還在用舊版 Axios,請先在最新版本線上重現問題,再判斷那是否仍是現在的行為;在正式部署前,也務必先在你自己的應用程式裡測試升級。
什麼時候你仍然需要明確指定 Agent
原生 proxy 設定對單一、固定、傳統的 proxy 來說已經夠用。但一旦你需要逐請求控制、proxy 輪替,或 SOCKS 支援,它就不夠了——Axios 內建選項本來就不是為這些需求設計的。這時候 HttpsProxyAgent 就派上用場,下面我會一步步說明。你可以把原生選項理解成「單一 proxy、單一用途時夠用」,而 agent 方案則是「真正適合正式環境的做法」。
Node v24 與 v22.21+ 的環境 Proxy 路徑
較新的 Node 版本內建了環境變數 proxy 模式,可透過 NODE_USE_ENV_PROXY=1 或 --use-env-proxy 旗標啟用。根據 Node 官方 CLI 文件,這功能是在 v24.0.0 加入,並回補到 v22.21.0——所以「Node 22+」其實不夠精確,應該是 v22.21.0 以及之後的版本。如果你用的是更早的 Node 22 patch,這個旗標根本不存在。
目前的 Axios 會透過 proxy-from-env 依賴來解析 HTTP_PROXY、HTTPS_PROXY 與 NO_PROXY,所以在這條 Axios 路徑上,不需要 global-agent。當 Node 自己的 env-proxy 模式也同時啟用時,路由判斷就可能涉及兩層機制。
Axios 文件也提到,在某些 Node 版本中,如果 agent 帶有 proxyEnv 屬性,Axios 會把處理交給 Node,而不是自己再做解析。實務上,這代表你應該只選一套機制,然後一路用到底:
- 讓 Node 處理: 啟用旗標,不設定 Axios 的
proxy,交給環境變數。 - 讓 Axios 處理: 不開 Node 旗標,讓 Axios 自己根據環境變數解析。
- 完全手動控制: 明確設定
proxy: false,並自己提供httpsAgent—— 這樣就能完全避開兩套自動機制;只要你需要輪替或逐請求邏輯,我會建議這麼做。
我實際測過 Axios 端的解析:在子程序環境中設定 HTTP_PROXY 後,請求確實會經過本機 proxy;再加上對應的 NO_PROXY 項目後,下一次請求也會正確略過 proxy。所以環境變數路徑現在真的可以開箱即用——你需要注意的是同時開啟雙模式的情境。
把 Proxy 接進 Axios 的 5 種方式(比較版)
在看程式碼前,先快速了解整體選項。我針對每一種方式都用真實的本機 proxy 環境做過測試,不只是讀文件而已。
| 方法 | HTTPS 支援 | 認證支援 | 可逐請求控制 | 適合輪替 | 複雜度 |
|---|---|---|---|---|---|
內嵌 proxy 選項 | ✅(目前 Axios) | ✅ | ✅ | ❌ | 低 |
axios.create() 預設值 | ✅(目前 Axios) | ✅ | ❌(整個 instance) | ❌ | 低 |
環境變數(HTTP_PROXY/HTTPS_PROXY) | ✅ | ✅ | ❌ | ❌ | 低 |
httpsAgent + HttpsProxyAgent | ✅ | ✅ | ✅ | ⚠️(手動) | 中 |
| Request interceptor + agent pool | ✅ | ✅ | ✅ | ✅ | 中高 |
如果你只是寫一支小腳本,要打到單一 proxy,就用內嵌選項。若同一個模組裡的每個請求都要走同一個 proxy,而且不想重複設定,就用 axios.create()。如果你的基礎設施團隊已經在集中管理 proxy 路由,而你只想沿用,那就用環境變數。當你需要原生設定做不到的控制力時,就改用明確的 agent;而只要「控制」升級成「輪替」,就該直接用 interceptor 模式。

逐步教學:Axios 的基本 Proxy 設定
最簡單的做法,就是直接在請求裡放入內建的 proxy 物件:
import axios from 'axios';
const res = await axios.get('https://httpbin.org/ip', {
proxy: {
host: '203.0.113.10',
port: 8080,
protocol: 'http',
},
});
console.log(res.data);
執行後,你應該會在回應裡看到 proxy 的 IP,而不是你自己的。若你是在本機搭配真實 proxy 測試,這通常不到一秒就能完成;相較之下,為了測一個請求就去手動設定系統級 proxy,往往白白浪費十五分鐘,真的很不划算。
把這次結果和基準值對照。成功時,顯示的應該是 proxy 的公開 IP,而不是你先前記錄的來源 IP。
用 axios.create() 設定整個 instance 的預設值
如果某個模組裡的所有請求都要走同一個 proxy,就把設定寫進 instance 裡,而不是每次重複寫:
const client = axios.create({
proxy: {
host: '203.0.113.10',
port: 8080,
},
timeout: 15_000,
});
const res = await client.get('https://httpbin.org/ip');
我也確認過,單筆請求上覆寫 proxy: false 可以乾淨地略過 instance 預設值——如果你 95% 的請求都要走 proxy,但少數幾個(例如 health check)不需要,這就很好用。
透過環境變數設定 Proxy
如果你的路由是集中管理的——例如 Docker 容器或 CI 環境,ops 已經幫你設定好 proxy 環境變數——那你甚至不用碰 Axios 設定:
export HTTP_PROXY=http://203.0.113.10:8080
export HTTPS_PROXY=http://203.0.113.10:8080
export NO_PROXY=localhost,127.0.0.1
目前 Axios 不需要 global-agent 就能讀取這些變數。只是要記得前面提過的 Node 版本界線:如果 NODE_USE_ENV_PROXY 也同時啟用,請明確定義到底是哪一層在負責路由,並在實際部署的 runtime 裡測試 NO_PROXY 的行為。
逐步教學:用 httpsAgent 做 HTTPS Proxy 設定(真正可控)
如果你需要的不只是「永遠用同一個 proxy」,這才是我真正推薦的做法。先安裝目前的 agent 套件:
npm install https-proxy-agent
https-proxy-agent 9.1.0 需要 Node 20 以上,並且會先向 proxy 發出正確的 CONNECT,再把目標連線穿過去。
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
const agent = new HttpsProxyAgent('http://203.0.113.10:8080');
const client = axios.create({
proxy: false, // 避免 Axios 原生解析也來插手
httpsAgent: agent,
timeout: 15_000,
});
const res = await client.get('https://httpbin.org/ip');
console.log(res.data);
當你用明確的 agent 負責路由時,請把 proxy: false 設上。這樣設定就很清楚,也能避免 Axios 原生或環境變數 proxy 解析和你提供的 agent 打架。
加上 Proxy 驗證資訊
把帳密直接塞進 proxy URL 即可:
const agent = new HttpsProxyAgent('http://myuser:mypassword@203.0.113.10:8080');
如果密碼裡有特殊字元——像 @、:、# 這幾個最常出事——請先做 percent-encode,或是把各個部分先用 encodeURIComponent() 編碼再組字串。密碼裡如果直接放一個原始 @,它會被解析成主機名稱區段的開始,最後就會得到一個看似跟編碼無關的連線錯誤。
在 Axios 中使用 SOCKS5 Proxy
SOCKS proxy 不能直接搭配 HttpsProxyAgent,你需要用支援該協定的不同 agent:
npm install socks-proxy-agent
import { SocksProxyAgent } from 'socks-proxy-agent';
const agent = new SocksProxyAgent('socks5://myuser:mypass@203.0.113.10:1080');
const client = axios.create({
proxy: false,
httpsAgent: agent,
});
socks-proxy-agent 10.1.0 也需要 Node 20 以上。當你面對的是只提供 SOCKS gateway 的企業網路,或是代理商提供比純 HTTP proxy 更彈性的協定支援時,SOCKS5 就很值得使用。
用 Axios Request Interceptor 做 Proxy 輪替
在呼叫端程式裡隨機挑一個 proxy,對一次性腳本來說還可以。但一旦你要發出幾百個請求,這種寫法就會開始失控:沒有集中地方追蹤哪些 proxy 已經掛了、沒有重試邏輯,而選 proxy 的程式也會被複製貼上得到處都是。Axios 的 interceptor 系統 可以把這段邏輯集中到一個可測試的地方;我在這篇文章的 SERP 競品教學裡,沒有看到任何一篇使用這種模式。

建立 Proxy Pool
import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
class ProxyPool {
private agents: HttpsProxyAgent<string>[];
private index = 0;
constructor(proxyUrls: string[]) {
this.agents = proxyUrls.map((url) => new HttpsProxyAgent(url));
}
next(): HttpsProxyAgent<string> {
const agent = this.agents[this.index];
this.index = (this.index + 1) % this.agents.length;
return agent;
}
}
const pool = new ProxyPool([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
]);
const client = axios.create({ timeout: 15_000 });
client.interceptors.request.use((config: InternalAxiosRequestConfig) => {
config.proxy = false;
config.httpsAgent = pool.next();
return config;
});
我用兩個本機 proxy 測過這段邏輯,確認請求確實會交替分配:proxy A、proxy B、再回到 A。要注意的是,Axios 執行 request interceptor 的順序是後進先出,所以如果你還有其他 interceptor(像是認證標頭或 logging),順序比你想像中更重要。
加上帶重試保護的 Response Interceptor
這就是大多數 DIY 輪替腳本開始變亂的地方。對每種錯誤都無腦重試,還搭配無上限的 proxy pool,會讓一個壞請求變成連鎖災難——尤其是 POST 這種非冪等方法,重試可能會讓你不想重複的副作用真的重複一次。
type RetryableConfig = InternalAxiosRequestConfig & {
__proxyRetryCount?: number;
};
client.interceptors.response.use(
undefined,
async (error: AxiosError) => {
const config = error.config as RetryableConfig | undefined;
if (!config) throw error;
const method = String(config.method ?? 'get').toUpperCase();
config.__proxyRetryCount ??= 0;
if (method !== 'GET' || config.__proxyRetryCount >= 1) throw error;
config.__proxyRetryCount += 1;
config.proxy = false;
config.httpsAgent = pool.next();
return client.request(config);
}
);
我用一個故意壞掉的 proxy 測過這段程式,確認只會在另一個 agent 上觸發一次重試——沒有無限迴圈,也不會對 POST 重試。這才是你要的界線:重試策略要明確知道哪些請求可以安全重放,而不是「先再試一次看看會不會好」這種偷懶做法。

錯誤診斷表:每種失敗都對應到修正方式
把這頁收藏起來。下面列的是真正會出現在 Axios GitHub issues 和 Stack Overflow 討論串裡的錯誤,不是天馬行空的假設。
| 錯誤 / 現象 | 可能原因 | 修正方式 |
|---|---|---|
ECONNREFUSED | host/port 設錯,或 proxy 伺服器已停止 | 先用 curl -x http://host:port target-url 驗證,再來看 Axios 程式碼 |
407 Proxy Authentication Required | 認證資訊缺失或錯誤 | 在 proxy 設定裡加入 auth: { username, password },或把帳密嵌入 HttpsProxyAgent 的 URL |
403 Forbidden | 來源站或 WAF 拒絕了請求或 proxy IP | 檢查網站的存取政策、登入驗證與請求頻率;不要把不同的 header 或 IP 當成繞過限制的許可 |
| 回應顯示你的真實 IP | NO_PROXY、proxy:false、明確的直接 agent,或歷史/特定版本設定正在繞過 proxy | 釐清到底是哪一層在負責路由;必要時用可控的 IP endpoint 與明確 agent 驗證路徑 |
ETIMEDOUT | 連線或回應時間超過設定的 timeout | 找出時間花在哪裡;只有在工作負載真的需要時才調整 timeout,否則應更換或暫停不健康的路由 |
回應中途出現 ECONNRESET | proxy、網路或來源站主動關閉連線 | 記錄是哪一跳失敗;只有可安全重放的請求才重試,而且要有上限 |
Nginx 後方出現 502 Bad Gateway | Nginx 的 proxy_pass 設定錯誤,或 Axios 的 timeout 與 Nginx 不一致 | 檢查 proxy_connect_timeout 和 proxy_read_timeout(預設都是 60 秒),並與 Axios 的 timeout 對齊 |
ERR_TLS_CERT_ALTNAME_INVALID | 目標使用了錯誤的 agent 類型,或是自簽憑證 | 確認你用的是對應協定的 agent;本機測試時可設 rejectUnauthorized: false,但正式環境絕對不要這麼做 |
快速除錯清單
當東西壞掉、但你一時看不出原因時,請照這個順序排查:
- 直接用
curl -x http://host:port https://your-target.com測 proxy。如果失敗,先查 proxy 連線、認證與目標站,不要急著改 Axios。如果成功,Axios 這條路徑還是要再獨立驗證。 - 確認你實際跑的 Axios 與 Node 版本,並在相同版本與相同設定下,對照歷史報告再決定要不要套用那些修正。
- 搞清楚到底是哪一層在解析 proxy:原生 Axios 設定、Axios 的環境變數解析、Node 內建 env-proxy 模式,還是你自己指定的 agent。絕對不要讓超過一個層級同時負責同一個請求。
- 檢查
NO_PROXY是否意外匹配到了主機名稱。 - 如果你用的是明確 agent,確認有設定
proxy: false,避免 Axios 想自己再處理一次。
什麼時候應該完全跳過自己拼 Proxy
如果你的真正目標是替任意流量做路由,例如企業網路測試、地理位置測試,或受控的網路出口,那前面這些內容都很實用。但很多人搜尋「怎麼在 Axios 設 proxy」,其實真正想要的是網站資料,而 proxy 只是手段,不是目的。
如果你是這種情況,不妨先想想:你到底真的需要 proxy,還是其實需要一個抓取 API 來幫你處理基礎架構。Thunderbit 的 Open API 只要給它 URL 和 schema,就能回傳結構化 JSON——不用處理原始 HTML、不用 agent 函式庫,也不用自己顧一整個 proxy pool。/extract 端點 可以在伺服器端處理 JS 渲染頁面、反機器人機制與 CAPTCHA;如果你只需要把頁面轉成乾淨 Markdown,還有更輕量的 /distill 端點。另外也有一個 MCP server,提供像 thunderbit_extract 和 thunderbit_suggest_fields 這類工具,讓 Claude 或 Cursor 這種 coding assistant 在任務中途就能抓到結構化資料,完全不用碰 proxy 設定,還有一個 CLI 可供終端機與 CI 工作流程使用。
| 關注點 | 自己用 Axios + Proxies | Thunderbit API/MCP/CLI |
|---|---|---|
| Proxy 來源與輪替 | 由你自己管理 | 由伺服器端處理 |
| 瀏覽器與存取挑戰 | 你要自己操作瀏覽器/網路層 | 由服務在其公開能力範圍內處理 |
| JS 渲染頁面 | 需要 headless browser | renderMode: full |
| 輸出格式 | 原始 HTML → 你自己解析 | 透過 schema 輸出結構化 JSON |
| 網站變動時的維護 | 由你維護 | 受管理的抽取層可減少部分應用端維護成本 |
老實說,如果你是為了測試或企業網路而需要轉送流量,那 Axios 和 proxy 設定還是無可取代。但如果你的交付物是結構化網頁資料,API-first 的做法,往往能少掉你自己要維護的 proxy、瀏覽器與解析程式碼。在 2026 年 8 月 7 日查閱時,Thunderbit API 的 rate limit 文件 顯示免費方案為每分鐘 10 次請求、同時 2 個請求。請把這些數字視為有時效性的 API 限制,並在正式依賴前重新確認頁面內容。
總結
這篇文章最核心的觀點,其實跟很多舊教學講的不一樣:目前 Axios 的文件與我記錄下來的本機測試都顯示,HTTPS 目標確實會使用正確的 CONNECT 穿隧。歷史上的失敗仍然重要,但它們必須放在特定版本與設定情境下解讀。原生設定是很適合入門的低複雜度做法;一旦你需要逐請求控制、SOCKS 支援或輪替,明確的 HttpsProxyAgent(或 SocksProxyAgent)搭配 proxy: false,能讓責任邊界更清楚。若你在正式環境中要輪替整個 proxy pool,request 與 response interceptor 會是集中、可測試的好地方——只是要記得,重試邏輯一定要有迴圈保護,而且只重放真正安全的請求。
把上面的診斷表收藏起來,下次凌晨兩點 proxy 設定又丟出莫名其妙的錯誤時,就能拿來對照。若你發現自己花在除錯 proxy 管線的時間,已經比真正使用資料還多,也許該想想:API-first 抽取工具 是否能更快解決真正的問題。
常見問題
Axios 原生支援 HTTPS proxy 嗎? 在目前版本中,對一般 HTTP proxy 來說是支援的:官方文件描述了 HTTPS 目標會走 CONNECT 穿隧,而 Axios 1.19.0 在本機記錄測試中也成功走通。歷史版本與特定 proxy 設定曾經真的出過問題,所以請務必確認實際版本與 proxy 設定,不要直接假設一定成功或一定失敗。
我要怎麼在 Axios 裡輪替 proxy?
可以用 request interceptor,在每次請求送出前從 proxy pool 指派不同的 httpsAgent,再搭配 response interceptor,讓失敗請求改用另一個 proxy 重試。重試邏輯要有上限——例如只重試一次,而且只針對像 GET 這類冪等方法——這樣才不會不小心重放不該重放的請求。
為什麼 Axios proxy 顯示的是我的真實 IP?
先檢查是不是 NO_PROXY、proxy:false、明確的直接 agent,或部署環境的路由設定把 proxy 繞過了。記得記錄 Axios/Node 版本,並用 cURL 單獨測試 proxy。如果你需要毫不含糊的逐請求路由,請用 HttpsProxyAgent 搭配 proxy:false,然後在可控的 endpoint 上確認實際看到的 IP。
Axios 可以使用 SOCKS5 proxy 嗎?
可以,透過 socks-proxy-agent 套件即可。建立 SocksProxyAgent 實例時填入 SOCKS URL,並把它傳給 Axios 的 httpsAgent;同時要確保你沒有再傳 HttpsProxyAgent,因為這兩種協定需要不同的 agent 類型。
Axios 的 proxy 選項和 httpsAgent 有什麼差別?
proxy 是 Axios 內建、用來處理單一固定 proxy 的設定,目前版本中很適合簡單用途。httpsAgent 則可以接入自訂的 Node.js agent,例如 HttpsProxyAgent 或 SocksProxyAgent,讓你能直接針對每個請求控制路由、認證與輪替——這些都是原生選項原本就不是為了處理的事。


