Socks5Proxy

Node.js代理设置:HTTP与SOCKS5代理连接fetch和https

本指南介绍Node.js 18+环境下,使用undici ProxyAgent连接Socks5Proxy的HTTP代理,用socks-proxy-agent连接SOCKS5代理,以及通过API获取并轮换代理列表的代码实现。

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配置代理地址,用户名密码通过token选项以Basic认证格式传递。将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 即可使用 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 模块运行,可通过传递代理使用代理。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的工具或测试场景。若需轮换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编码的username:password组合。ECONNREFUSED通常是端口错误,HTTP代理需使用HTTP端口,SOCKS代理需使用SOCKS5端口。

  • fetch和ProxyAgent同属undici包
  • 407:检查token值与注册IP
  • ECONNREFUSED: 区分HTTP端口与SOCKS5端口
  • 全请求超时控制
Node.js代理设置:undici·SOCKS5代理连接 | Socks5Proxy