Socks5Proxy

Node.js代理設定:HTTP與SOCKS5代理連接fetch與https

本指南說明Node.js 18+環境下,使用undici的ProxyAgent連接Socks5Proxy的HTTP代理,以socks-proxy-agent連接SOCKS5代理,並透過API輪換IP列表的實作程式碼。

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 端口
  • 為所有請求設定時間限制
Node.js代理設定:undici·SOCKS5代理連接 | Socks5Proxy