Настройка прокси в Node.js: Axios, Fetch, Undici и ротация
Опция прокси в axios является ловушкой для HTTPS-целей, а встроенный fetch полностью игнорирует ваши переменные окружения прокси. Вот настройка, которая работает с axios, fetch и undici — агенты, аутентификация, SOCKS5, ротация и потоковая передача.
Маршрутизация запросов Node.js через прокси выглядит как однострочник, но превращается в полдня отладки. Причина в том, что три HTTP-клиента, которые используют большинство проектов — axios, встроенный fetch, который появился в Node 18, и библиотека undici — каждый по-разному обрабатывают прокси, и ни один из них не ведет себя так, как вы ожидаете. В axios есть встроенная конфигурация proxy, которая документирована, работает только в Node и тихо ломается для HTTPS-целей за HTTP-прокси: ошибка, которая открыта на GitHub axios с 2020 года и вызвала популярную тему на Stack Overflow. Встроенный fetch, тем временем, игнорирует переменные окружения HTTP_PROXY и вообще не имеет опции прокси. Это руководство дает вам настройку, которая действительно работает в каждом клиенте, плюс аутентификация, SOCKS5, ротация и потоковая передача.
Конфигурация прокси в axios против прокси-агентов
Axios поставляется с объектом proxy — { host, port, auth } — и он отлично работает для обычных HTTP-целей. Ловушка в HTTPS: когда цель — https://, а прокси говорит на HTTP, axios не может открыть туннель CONNECT, и ваш запрос либо зависает, либо возвращается с вашим реальным IP. Решение, на котором сообщество остановилось, — полностью обойти встроенную конфигурацию и передать axios прокси-агент, затем установить proxy: false, чтобы два механизма не конфликтовали:
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
// Note the destructured import — a default import is the classic gotcha.
const agent = new HttpsProxyAgent("http://USER:PASS@gate.quantumproxies.io:PORT");
const client = axios.create({
httpAgent: agent, // for http:// targets
httpsAgent: agent, // for https:// targets
proxy: false, // disable axios' own broken proxy handling
timeout: 15000,
});
const r = await client.get("https://httpbin.org/ip");
console.log(r.data); // { origin: "<proxy exit IP>" }
Две детали экономят часы. Во-первых, используйте деструктурированный импорт { HttpsProxyAgent } — в последних версиях он экспортируется как именованный символ, а импорт по умолчанию дает объект, который вызывает ошибку при создании. Во-вторых, схема URL прокси остается http://, даже если прокси передает HTTPS-трафик: схема описывает, как вы достигаете прокси, а TLS к цели проходит внутри туннеля. Та же ошибка встречается в Python; если вы также работаете с requests, эти шаблоны перекликаются с нашим руководством по исправлению ProxyError и SSLError.
Аутентификация и переменные окружения
Аутентифицированные прокси используют учетные данные HTTP Basic. С агентом встраивайте их в URL как http://user:pass@host:port; если пароль содержит @, : или /, сначала закодируйте его с помощью encodeURIComponent(), иначе URL разделится в неправильном месте. Сообщение 407 Proxy Authentication Required означает, что учетные данные были отклонены или ваш исходный IP не включен в белый список. Axios также читает HTTP_PROXY, HTTPS_PROXY и NO_PROXY из окружения — удобно для проксирования сторонней библиотеки без изменения ее кода — и вы отключаете это, установив proxy: false. Важное предупреждение: встроенный fetch не читает эти переменные, так что скрейпер, который полагается на проксирование через переменные окружения, тихо идет напрямую, как только вы переключаетесь с axios на fetch.

Проксирование встроенного fetch с undici
Глобальный fetch в Node построен на undici, и именно там живет прокси. Вы создаете ProxyAgent и передаете его как нестандартную опцию dispatcher — это современный, легкий по зависимостям способ проксирования fetch, и он корректно обрабатывает HTTPS CONNECT из коробки:
import { ProxyAgent } from "undici";
const dispatcher = new ProxyAgent({
uri: "http://gate.quantumproxies.io:PORT",
token: "Basic " + Buffer.from("USER:PASS").toString("base64"),
});
const res = await fetch("https://httpbin.org/ip", { dispatcher });
console.log(await res.json());
Если вы используете undici напрямую, а не глобальный fetch, тот же ProxyAgent подключается к request() или к setGlobalDispatcher(), чтобы проксировать каждый fetch в процессе сразу. Этот глобальный переключатель в одно действие — самый чистый способ маршрутизации всего кода через прокси без передачи диспетчера через каждую функцию.
SOCKS5-прокси в Node.js
Ни axios, ни undici не поддерживают SOCKS нативно — передайте строку socks5:// в конфигурацию proxy в axios, и вы получите утверждение о несоответствии протокола. Установите socks-proxy-agent и используйте его так же, как и агент HTTPS, подключив к httpAgent и httpsAgent. Предпочитайте socks5h:// вместо socks5://: завершающая h разрешает DNS на стороне прокси, что предотвращает утечки DNS и разрешает геоограниченные имена хостов из точки выхода. Каждый план SOCKS5-прокси предоставляет тот же шлюз через HTTP и SOCKS5, так что это смена схемы, а не новая покупка:
import axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://USER:PASS@gate.quantumproxies.io:PORT");
const client = axios.create({ httpAgent: agent, httpsAgent: agent });
const r = await client.get("https://httpbin.org/ip");
console.log(r.data);
Ротация без списка прокси
Старый рецепт — массив IP, Math.random() для каждого запроса, удаление неработающих — это код, который вы больше не поддерживаете. Вращающийся шлюз назначает новый выходной IP на стороне сервера для каждого запроса, так что одна конечная точка ведет себя как целый пул. Через вращающиеся резидентные прокси этот пул охватывает более 90 миллионов IP в более чем 200 странах, и цикл ниже выводит разное происхождение на каждой итерации без логики ротации:
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USER:PASS@gate.quantumproxies.io:PORT");
const client = axios.create({ httpAgent: agent, httpsAgent: agent, proxy: false });
for (let i = 0; i < 3; i++) {
const r = await client.get("https://httpbin.org/ip");
console.log(r.data.origin); // a different exit IP each time
}
Когда поток охватывает несколько запросов — вход в систему, добавление в корзину, оформление — ротация для каждого запроса нарушает сессию. Параметр липкой сессии в имени пользователя прокси закрепляет один выходной IP на заданное время, затем вращается; та же конечная точка, одно изменение строки. Если вы масштабируете это до тысяч одновременных запросов, перенесите работу с циклов axios и прочитайте наше руководство по архитектуре крупномасштабного скрейпинга для очередей и бюджетов параллелизма.
Потоковые ответы через прокси
Загрузка файлов или больших JSON-пакетов работает так же, как и любой запрос, как только агент подключен — установите responseType: "stream" и направьте тело на диск. Прокси обрабатывает передачу прозрачно, так что экспорт размером 200 МБ никогда не буферизуется в памяти:
import fs from "node:fs";
const r = await client.get("https://example.com/large.json", {
responseType: "stream",
});
r.data.pipe(fs.createWriteStream("out.json"));

Часто задаваемые вопросы
Почему мой прокси в axios не работает?
Наиболее распространенная причина — HTTPS-цель за HTTP-прокси: встроенная конфигурация proxy в axios не может открыть туннель CONNECT и возвращает ваш реальный IP или зависает. Переключитесь на прокси-агент — подключите HttpsProxyAgent к httpAgent и httpsAgent, и установите proxy: false, чтобы axios перестал пытаться обрабатывать прокси самостоятельно.
Поддерживает ли axios SOCKS5-прокси?
Не нативно — передача URL socks5:// в конфигурацию proxy вызывает ошибку несоответствия протокола. Установите socks-proxy-agent, создайте SocksProxyAgent и подключите его к httpAgent и httpsAgent. Используйте схему socks5h://, чтобы DNS разрешался на стороне прокси, а не утекал с вашего компьютера.
Как использовать прокси с встроенным fetch в Node.js?
Встроенный fetch не имеет опции прокси и игнорирует переменные окружения HTTP_PROXY. Создайте ProxyAgent в undici и передайте его как опцию dispatcher в вызове fetch, или вызовите setGlobalDispatcher() один раз, чтобы проксировать каждый fetch в процессе. Undici корректно обрабатывает HTTPS CONNECT без дополнительной конфигурации.
Как установить прокси в axios с помощью переменных окружения?
Экспортируйте HTTP_PROXY, HTTPS_PROXY и, при необходимости, NO_PROXY с полными URL прокси; axios читает их автоматически. Установите proxy: false в запросе или экземпляре, чтобы axios игнорировал окружение. Помните, что это касается только axios — undici и встроенный fetch не будут использовать эти переменные.
Вся история умещается на карточке: axios нужен агент и proxy: false, встроенному fetch нужен диспетчер undici, SOCKS нужен свой агент, а ротация должна быть на шлюзе, а не в вашем цикле. Настройте правильно, и последняя переменная — качество IP — чистый резидентный выход проходит там, где отмеченный датацентр IP получает 403 на том же коде.
Получите резидентные прокси, которые проходят с первого запроса