Настройка прокси в Node.js: подключение HTTP и SOCKS5 к fetch и https
Это руководство объясняет, как подключить HTTP-прокси Socks5Proxy через ProxyAgent в undici и SOCKS5-прокси через socks-proxy-agent в Node.js 18 и выше, а также как циклически использовать список через API.
Что нужно для использования прокси в Node.js?
Встроенный fetch в Node.js работает на библиотеке undici и по умолчанию не читает настройки прокси. Поэтому HTTP-прокси передается через ProxyAgent из undici в качестве dispatcher, а SOCKS5-прокси передается через socks-proxy-agent в качестве агента для модуля https Node.js.
Пример использует IP 198.51.100.23, HTTP-порт 8000, SOCKS5-порт 1080, имя пользователя spx_user, пароль spx_pass. Весь код приведён в формате ES-модулей (.mjs).
npm install undici socks-proxy-agentКак подключить HTTP прокси к fetch?
Укажите адрес прокси в ProxyAgent, а имя пользователя и пароль - в token-опции как Basic-аутентификацию. Передайте dispatcher в fetch из undici, и запрос пойдет через прокси. 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 - это агент для использования с модулями http и https в Node. Формат socks5h означает, что разрешение доменных имён выполняется на стороне прокси. Пример ниже передаёт агент в https.get и выводит тело ответа.
Библиотеки, работающие поверх http модуля, такие как axios, могут использовать SOCKS5, если передать одинаковый агент в httpAgent и httpsAgent.
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 и создаете агента для каждого прокси, используя следующий агент для каждого запроса. Код ниже получает HTTP-список в формате ip:port:user:pass, создает массив 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?
Если зарегистрировать IPv4 сервера, где запущен Node.js, в панели управления, то в ProxyAgent можно использовать только адрес без токена. SOCKS5 также можно использовать без логина и пароля, например socks5h://198.51.100.23:1080. Это упрощает развертывание на нескольких серверах, так как пароль не нужно хранить в переменных окружения или коде.
Как подключиться с axios?
axios работает поверх http и https модулей Node, поэтому можно передать агент для прокси. Для SOCKS5 используйте socks-proxy-agent в httpAgent и httpsAgent, а proxy в axios установите в false, чтобы избежать конфликта.
В 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.
Равномерное распределение запросов между прокси предотвращает перегрузку. Общие тарифы поддерживают до 500 одновременных соединений на IP.
Можно ли применить прокси ко всем запросам через переменные среды?
EnvHttpProxyAgent из undici использует переменные 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());Как решить распространенные проблемы?
Если кажется, что dispatcher игнорируется во встроенном fetch Node.js, проверьте, импортировали ли вы fetch из пакета undici. Если версии встроенного fetch и установленного undici различаются, агент может не работать, поэтому самый надежный способ - импортировать fetch и ProxyAgent из одного пакета.
Ответ 407 означает ошибку аутентификации. Убедитесь, что после Basic в token указано имя пользователя и пароль в base64. ECONNREFUSED часто возникает из-за неверного порта. Используйте HTTP порт для HTTP агентов и SOCKS5 порт для SOCKS агентов.
- fetch и ProxyAgent находятся в одном пакете undici
- 407: проверьте token и зарегистрированные IP
- ECONNREFUSED: различие между HTTP- и SOCKS5-портами
- Ограничение времени для всех запросов