Перейти к содержанию

Руководство · На русском

Прокси для Node.js fetch через Undici

Настройте явный маршрут для Node.js fetch, выполните небольшой HTTPS-запрос и проверьте завершение работы после ошибки. Пример использует ProxyAgent из Undici, хранит пароль вне кода и различает отказ туннеля и ответ сайта назначения.

Инструкции в этом разделе — на русском. Магазин, личный кабинет, документация и условия заказа пока доступны на английском.

Опубликовано:

Короткие ответы

Как указать прокси для Node.js fetch?

Создайте ProxyAgent и передайте его в параметре dispatcher функции fetch из Undici. В этом руководстве клиент и агент импортируются из одного установленного пакета. Настройки такого запроса не распространяются автоматически на другие HTTP-клиенты процесса.

Куда передавать логин и пароль прокси?

Адрес шлюза передаётся в uri, а значение заголовка Basic — в token. Не добавляйте пароль шлюза в заголовки запроса к сайту. Полное имя пользователя и пароль считываются из настроек запуска.

Почему HTTPS_PROXY может не сработать?

Поддержка переменных окружения зависит от версии Node.js, используемого клиента и способа его запуска. Наличие переменной в терминале не доказывает, что рабочий процесс применил её. Здесь маршрут задан прямо в параметрах запроса.

Что означает сообщение fetch failed?

Оно может скрывать ошибку соединения, авторизации, сертификата или ожидания. Само сообщение не означает, что сайт вернул HTTP-ошибку. Проверьте причину локально и сравните те же настройки с небольшим запросом через curl.

Подготовьте совместимый клиент и подключение

Встроенный fetch в Node.js и пакет Undici из зависимостей приложения могут иметь разные версии. Поэтому пример импортирует и fetch, и ProxyAgent из одного пакета. Выберите поддерживаемую версию Node.js, совместимую с устанавливаемой библиотекой. Проверяйте именно среду рабочего процесса: контейнер и локальный терминал могут запускать разные версии.

Установка и проверка версийsh
node --version
npm install undici
npm ls undici

Сохраните файл блокировки зависимостей вместе с приложением. Он позволяет повторить проверенную установку при развёртывании. Требования к среде опубликованы в документации Undici — на английском. Откройте настройки подключения — на английском, выберите HTTP, пул, доступную страну и режим ротации. Передайте полное сгенерированное имя пользователя в PROXY_USER, пароль прокси — в PROXY_PASSWORD.

Используйте настройки секретов вашего окружения, а не строки с паролем в исходном файле или истории команд. Необязательная переменная PROXY_SERVER содержит только схему, хост и порт. Если проверка через curl уже проходит, перенесите те же параметры. Не меняйте одновременно страну, пароль и клиент: при ошибке станет трудно определить причину.

Выполните небольшой HTTPS-запрос

Сохраните файл как proxy-check.mjs и запустите node proxy-check.mjs. Echo-сервис возвращает адрес, с которого получил запрос. Скрипт печатает HTTP-код и этот адрес, не выводя учётные данные. Сообщения внутри примера оставлены на английском, чтобы код совпадал с исходным руководством.

Код и сообщения программы совпадают с английским исходным примером.

Проверка маршрута: proxy-check.mjsjavascript
import { ProxyAgent, fetch } from 'undici';

function required(name) {
  const value = process.env[name];
  if (!value) throw new Error('Missing ' + name);
  return value;
}

async function main() {
  const username = required('PROXY_USER');
  const password = required('PROXY_PASSWORD');
  const dispatcher = new ProxyAgent({
    uri: process.env.PROXY_SERVER ?? 'http://gw.portproof.org:7000',
    token: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'),
  });

  const signal = AbortSignal.timeout(30_000);
  try {
    const response = await fetch('https://api.portproof.org/v1/echo-ip', {
      dispatcher,
      signal,
    });
    const text = await response.text();
    if (!response.ok) throw new Error('HTTP status ' + response.status);
    const payload = JSON.parse(text);
    if (typeof payload.ip !== 'string') {
      throw new Error('Echo did not return an IP address');
    }
    console.log('HTTP', response.status, 'exit', payload.ip);
  } finally {
    if (signal.aborted) await dispatcher.destroy();
    else await dispatcher.close();
  }
}

main().catch((error) => {
  console.error('Proxy check failed:', error.cause?.code ?? error.name);
  process.exitCode = 1;
});

Сначала читается тело, затем проверяются статус и структура JSON. Это освобождает ресурсы ответа и при обычной HTTP-ошибке. Проверка наличия строкового поля ip относится к формату этого echo-сервиса. Успешный результат подтверждает маршрут конкретного запроса; он не гарантирует доступность другого сайта, нужную страну по сторонней базе или полезность будущего результата.

Разделите параметры шлюза и сайта

Поле token содержит всё значение Basic-заголовка. Код соединяет имя пользователя и пароль через двоеточие, после чего кодирует строку в Base64. Пароль не вставляется в URL, поэтому его знаки @, / или % не становятся частью адреса. Передавайте исходные значения. Имя пользователя для Basic не должно содержать двоеточие; используйте целиком имя из конструктора подключения.

Base64 не шифрует пароль. Закодированный токен и полный объект агента тоже являются секретами. Не включайте их в общие журналы, отчёты об ошибках или примеры для поддержки. Заголовок Authorization для API сайта относится к другой системе входа. Заголовок Proxy-Authorization не нужно добавлять в обычный запрос: авторизацией шлюза занимается агент.

Для HTTPS-адреса HTTP-шлюз открывает туннель CONNECT, после чего клиент устанавливает TLS с сайтом. Схема шлюза остаётся http://. Само HTTP-подключение к шлюзу не получает шифрование от HTTPS-адреса назначения. Проверка сертификата сайта должна оставаться включённой. Интерфейс токена описан в справочнике ProxyAgent — на английском.

Используйте параметр своего HTTP-клиента

В примерах для node:https и некоторых библиотек используется agent, но Undici принимает dispatcher. Эти объекты нельзя считать взаимозаменяемыми только из-за похожего назначения. Если проект использует другой клиент, сначала проверьте его интерфейс настройки. Передача ProxyAgent в неподдерживаемое поле не доказывает, что запрос отправился через выбранный маршрут.

Этот пример относится к HTTP-прокси. Поддержку SOCKS нужно проверять у конкретной версии клиента и агента, вместе с соответствующим протоколом и портом. Не переносите настройки браузера в fetch механически. Для настоящей браузерной навигации есть отдельное руководство по Playwright, где прокси принадлежит браузеру или его контексту.

Ограничьте ожидание и завершите чтение тела

Сигнал с таймаутом тридцать секунд действует во время запроса и чтения тела. Это пример бюджета ожидания, а не обещание скорости сети. В большом задании дополнительно ограничьте общую продолжительность, число работников и размер очереди. Если ответ больше небольшого echo-объекта, читайте его потоком с явным пределом байтов: текущий пример загружает всё тело в память.

Нельзя рассчитывать только на сборщик мусора. Тело ответа следует прочитать или отменить, иначе соединения могут остаться занятыми. В сервисе повторно используйте dispatcher для стабильной конфигурации и закрывайте его при завершении соответствующей работы. Создание нового агента для каждой операции лишает приложение повторного использования соединений и усложняет освобождение ресурсов.

Есть отдельная граница: завершение fetch по таймауту не ставит срок на последующий await dispatcher.close(). Мягкое закрытие ждёт окончания работы. Поэтому пример вызывает destroy(), если его сигнал уже отменён, а после успешного запроса использует close(). Такое принудительное завершение подходит для агента, принадлежащего одному проверочному запросу. Общий агент сервиса требует другой политики, иначе таймаут одной задачи отменит чужую работу.

Что проверялось локально

30 сентября 2026 года для английского исходного руководства проверяли Node.js 22.22.0 и отдельно установленный Undici 7.29.1. Локальный прокси с тестовой авторизацией задерживал ответ CONNECT на 1500 мс, а клиент использовал таймаут 250 мс. Это проверка поведения закрытия соединения; рабочий шлюз и платные пулы в ней не участвовали.

Один зафиксированный локальный запуск
Завершение после отменыОшибка fetchОкончание закрытия
Мягкое close()254 мс1516 мс
Условное destroy() после отмены255 мс259 мс

Дополнительно проверялось прерывание медленного тела после получения заголовков и сохранение мягкого закрытия после успешного ответа. Планировщик влияет на длительность, поэтому эти значения нельзя переносить на реальные подключения. Русская страница использует тот же код без изменений; новых измерений сети или отдельного полного набора испытаний она не заявляет.

Проверьте окружение и повторные соединения

Новые версии Node.js предлагают включаемую поддержку переменных прокси; доступность параметров запуска зависит от версии. Сверьтесь со справочником Node.js — на английском. В Undici есть EnvHttpProxyAgent для намеренного использования переменных окружения. Его документация — на английском объясняет приоритеты и исключения. Исключённый адрес может открываться напрямую.

Один вызов fetch не равен новому соединению. Повторное использование соединения влияет на наблюдение ротации; одинаковый адрес в двух ответах не обязательно означает неисправность. Для связанной задачи сохраните полное имя выбранной sticky-сессии. Она сохраняет устройство, пока оно доступно, но адрес может измениться. Подробности — в руководстве по сессиям.

Выберите проверку по месту отказа

Частые ошибки Node.js fetch
НаблюдениеСледующая проверка
Ошибка импортаУстановка совместимого пакета в рабочем окружении.
Отказ авторизации проксиПолное имя, пароль и баланс; ошибка 407.
Ошибка сертификатаИмя сайта, время системы и доверенная цепочка сертификатов.
TimeoutError или отменаДоступность шлюза, бюджет ожидания и стадия чтения ответа.
HTTP 403 или 429Правила доступа и ограничение частоты на ответившем сервисе.

Подробную причину ошибки исследуйте локально, удаляя секреты перед передачей журнала. После echo проверьте один разрешённый запрос приложения и его содержание. Повторяйте только безопасные операции с ограниченным числом попыток. Не увеличивайте параллельность, пока не понятны результат, время и расход каждой задачи.

Допустимое использование

Используйте прокси для разрешённых проверок, мониторинга и исследований с соблюдением правил сайта. Политика допустимого использования — на английском.

Следующий шаг

Прокси для Node.js fetch через Undici · Portproof