Node.js使用代理需要什麼?
Node.js內建fetch實際由undici庫驅動,預設不讀取代理設定。HTTP代理需將undici的ProxyAgent作為dispatcher傳入,SOCKS5代理則需將socks-proxy-agent作為agent傳入Node的https模組。
範例使用 IP 198.51.100.23,HTTP 端口 8000,SOCKS5 端口 1080,帳號 spx_user,密碼 spx_pass。所有程式碼均為 ES 模組格式(.mjs)。
npm install undici socks-proxy-agent如何在 fetch 中連接 HTTP 代理?
將代理地址填入ProxyAgent,帳密以Basic認證格式填入token選項。傳入undici的fetch作為dispatcher即可透過代理發送請求。HTTPS地址會以CONNECT方式加密傳遞。
重複使用相同的ProxyAgent進行多個請求,連接會被重用,速度更快。為每個代理創建一個代理並輪流使用即可。
import { fetch, ProxyAgent } from "undici";
const agent = new ProxyAgent({
uri: "http://198.51.100.23:8000",
token: "Basic " + Buffer.from("spx_user:spx_pass").toString("base64"),
});
const res = await fetch("https://api.ipify.org?format=json", { dispatcher: agent });
console.log(res.status, await res.json()); // "ip" should be the proxy IP如何連接 SOCKS5 代理?
socks-proxy-agent 是與 Node 的 http、https 模組搭配使用的代理工具。使用 socks5h 地址時,域名解析會由代理伺服器處理。以下範例示範如何將代理傳入 https.get 並收集回應內容輸出。
類似 axios 這種基於 http 模組運作的函式庫,只需在 httpAgent 和 httpsAgent 中設定相同的 agent 即可透過 SOCKS5 發送請求。
import https from "node:https";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://spx_user:spx_pass@198.51.100.23:1080");
https.get("https://api.ipify.org?format=json", { agent }, (res) => {
let body = "";
res.on("data", (chunk) => (body += chunk));
res.on("end", () => console.log(res.statusCode, body));
}).on("error", (err) => console.error("request failed:", err.message));如何透過API獲取列表並輪流使用?
開始時透過API獲取列表,並為每個代理創建代理,每次請求時使用下一個代理。以下代碼以ip:port:user:pass格式獲取HTTP列表,創建ProxyAgent數組,若失敗則嘗試下一個代理。
請在請求中加入AbortSignal.timeout來設定時間限制。如果累積了無回應的請求,整個任務會變慢。
import { fetch, ProxyAgent } from "undici";
const API = "https://socks5proxy.io/api/v1";
const KEY = "YOUR_API_KEY";
const text = await (await fetch(API + "/proxies/download?format=ip:port:user:pass&protocol=http", {
headers: { Authorization: "Bearer " + KEY },
})).text();
const agents = text.trim().split("\n").map((line) => {
const [ip, port, user, pass] = line.trim().split(":");
return new ProxyAgent({
uri: "http://" + ip + ":" + port,
token: "Basic " + Buffer.from(user + ":" + pass).toString("base64"),
});
});
let i = 0;
async function get(url, tries = 3) {
for (let t = 0; t < tries; t++) {
const dispatcher = agents[i++ % agents.length];
try {
const res = await fetch(url, { dispatcher, signal: AbortSignal.timeout(20000) });
if (res.ok) return await res.text();
} catch {
// try the next proxy
}
}
return null;
}
console.log((await get("https://example.com/"))?.length);使用 IP 授權後代碼有何變化?
在儀表板註冊Node.js伺服器的IPv4後,ProxyAgent只需填入IP位址無需token參數。SOCKS5也可直接使用socks5h://198.51.100.23:1080格式免帳密認證。免除密碼寫入環境變數或程式碼的需求,更便於多伺服器部署。
若使用 axios 該如何連接?
axios 基於 Node 的 http、https 模組運作,可透過傳遞 agent 使用代理。SOCKS5 需將 socks-proxy-agent 設定為 httpAgent 和 httpsAgent,並將 axios 本身的 proxy 選項設為 false 以避免設定衝突。
HTTP 代理可透過 axios 的 proxy 選項設定 host/port/auth,但對 HTTPS 地址建議採用 agent 模式更穩定。使用 https-proxy-agent 套件可統一處理 HTTP 代理連接結構。
import axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://spx_user:spx_pass@198.51.100.23:1080");
const client = axios.create({ httpAgent: agent, httpsAgent: agent, proxy: false, timeout: 20000 });
const { data } = await client.get("https://api.ipify.org?format=json");
console.log(data);同時發送多個請求時需要注意什麼?
用Promise.all同時發送數千請求會導致連線過載,對代理與目標網站造成負擔。建議設定並行處理上限,使用p-limit等套件或自建任務隊列控制流量。
平均分配各代理的並發連接數,可避免單一 IP 負載過高。共享方案已包含 500 個並發連接,請將總並發請求數控制在此範圍內。
能否透過環境變數為所有請求套用代理?
undici 的 EnvHttpProxyAgent 會讀取 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 環境變數來設定代理。透過 setGlobalDispatcher 註冊後,該進程的所有 fetch 請求都會經過代理。對於內部使用 fetch 的多個函式庫,可一次套用設定相當方便。
全域設定會讓所有請求使用相同IP,較適合需單一國家連線的工具或測試,而非需分配IP的爬取任務。若需輪換,請如前所述透過dispatcher傳遞每個請求。
// HTTPS_PROXY=http://spx_user:spx_pass@198.51.100.23:8000 node app.mjs
import { EnvHttpProxyAgent, setGlobalDispatcher, fetch } from "undici";
setGlobalDispatcher(new EnvHttpProxyAgent());
const res = await fetch("https://api.ipify.org");
console.log(await res.text());如何解決常見問題?
若Node.js內建fetch傳入dispatcher後似乎無效,請確認是否從undici套件導入fetch。內建fetch與undici版本不同可能導致代理不相容,建議從同一套件導入fetch與ProxyAgent最可靠。
407回應表示認證資訊錯誤。請確認token值中Basic後是否包含使用者名稱:密碼的base64編碼值。ECONNREFUSED通常是端口錯誤。HTTP代理請使用HTTP端口,SOCKS代理請使用SOCKS5端口。
- fetch 和 ProxyAgent 同屬 undici 套件
- 407:檢查token值與註冊IP
- ECONNREFUSED: 區分 HTTP 端口與 SOCKS5 端口
- 為所有請求設定時間限制