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

如何將HTTP代理連接至fetch?

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傳遞agent並收集響應內容輸出。

如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中只需填入地址,無需使用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 地址中使用代理的方式更穩定。使用 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請求均經代理傳送,適用於多函式庫整合情境。

全局設置會讓所有請求使用相同的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