Короткие ответы
Как передать прокси с логином и паролем в Axios?
В показанном варианте HttpsProxyAgent передаётся как httpsAgent, а proxy: false отключает собственный выбор прокси Axios. Выбран HTTP-адаптер Node.js. Исходные секреты поступают из конфигурации процесса, не из опубликованного кода.
Сработает ли этот код во frontend?
Нет. Браузерный JavaScript не задаёт сетевой прокси через httpsAgent. Выполняйте пример на сервере Node.js и не помещайте пароль в frontend-переменные, сборку или ответ клиенту.
Почему HTTPS-запрос использует http://?
Схема описывает соединение до шлюза. CONNECT создаёт туннель, после чего внутри него выполняется TLS с назначением. Сам HTTP-канал до шлюза и его Basic-авторизация этим не шифруются.
Достаточно HTTP 200 для успешной проверки?
Нет. В примере отдельно требуются успешный CONNECT, статус назначения 200 и JSON с корректным IP. Ответ не подтверждает страну, скорость или результат другого сайта.
Зафиксируйте среду и транспорт
Оригинальный пример использует Node.js 22.22.0, Axios 1.20.0 и https-proxy-agent 9.1.0. Это зафиксированная комбинация, а не обещание совместимости любой новой версии. Перед переносом в рабочий проект проверьте его runtime, lockfile и выбранный адаптер; установка зависимостей сама по себе не проверяет сетевой маршрут.
npm install --save-exact axios@1.20.0 https-proxy-agent@9.1.0
node --version
npm ls axios https-proxy-agentОфициальная конфигурация Axios различает пользовательские агенты, proxy и адаптеры. Здесь явно выбран adapter: http. Переход на fetch-адаптер меняет настройку транспорта; не считайте параметры одного адаптера универсальными для всех.
Подготовьте секреты только для процесса
В Connection builder · English выберите HTTP и копируйте полное имя пользователя с нужными параметрами пула, страны и ротации. Передайте исходные значения как PROXY_USER и PROXY_PASSWORD через свой механизм секретов. PROXY_SERVER при необходимости задаёт только адрес HTTP-шлюза, без встроенных учётных данных.
| Параметр | Для чего нужен |
|---|---|
| httpsAgent | В этом примере открывает туннель и задаёт его маршрут. |
| proxy: false | Отключает конкурирующий выбор прокси самим Axios. |
| PROXY_USER / PROXY_PASSWORD | Авторизация шлюза, а не вход на сайт назначения. |
| auth или Authorization запроса | Относятся к назначению; не место для пароля прокси. |
| Переменные браузерной сборки | Не должны содержать секрет подключения. |
Код кодирует логин и пароль по отдельности ровно один раз. Передавайте исходный пароль, а не уже преобразованный URL. Двоеточие в логине отклоняется из-за разделителя Basic-авторизации. Не печатайте URL агента, весь объект ошибки Axios или его config: внутри могут остаться секреты.
Выполните один ограниченный запрос
Сохраните файл как axios-check.mjs и запустите node axios-check.mjs в подготовленной среде. Назначение берётся из конфигурации руководства. Используйте только разрешённый небольшой ресурс; не заменяйте проверку покупкой, отправкой формы или рабочим запросом с личными данными.
import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { isIP } from 'node:net';
function required(name) {
const value = process.env[name];
if (!value) throw new Error('Missing runtime setting');
return value;
}
async function main() {
const proxy = new URL(process.env.PROXY_SERVER ?? 'http://gw.portproof.org:7000');
if (proxy.protocol !== 'http:' || !proxy.hostname || proxy.username ||
proxy.password || proxy.pathname !== '/' || proxy.search || proxy.hash) {
throw new Error('Invalid gateway URL');
}
const username = required('PROXY_USER');
if (username.includes(':')) throw new Error('Invalid Basic username');
proxy.username = encodeURIComponent(username);
proxy.password = encodeURIComponent(required('PROXY_PASSWORD'));
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 20_000);
const agent = new HttpsProxyAgent(proxy, {
keepAlive: false, maxSockets: 1, signal: controller.signal,
});
let connectStatus;
agent.on('proxyConnect', (response) => { connectStatus = response.statusCode; });
try {
const response = await axios.get('https://api.portproof.org/v1/echo-ip', {
adapter: 'http', httpsAgent: agent, proxy: false,
signal: controller.signal, timeout: 10_000,
maxRedirects: 0, maxContentLength: 65_536, maxBodyLength: 0,
responseType: 'text', transformResponse: [(body) => body],
validateStatus: () => true,
});
if (connectStatus !== 200) {
throw new Error('Proxy CONNECT status ' + connectStatus);
}
if (response.status !== 200) {
throw new Error('Destination HTTP status ' + response.status);
}
const payload = JSON.parse(response.data);
if (!payload || typeof payload.ip !== 'string' || !isIP(payload.ip)) {
throw new Error('Invalid echo JSON');
}
console.log('HTTP', response.status, 'exit', payload.ip);
} catch (error) {
if (connectStatus && connectStatus !== 200) {
console.error('Proxy CONNECT status', connectStatus);
} else if (controller.signal.aborted) {
console.error('Request deadline exceeded');
} else if (axios.isAxiosError(error)) {
console.error('Request failed:', error.code ?? 'AXIOS_ERROR');
} else {
console.error(error instanceof SyntaxError ? 'Invalid echo JSON' : error.message);
}
process.exitCode = 1;
} finally {
clearTimeout(timer);
controller.abort();
agent.destroy();
}
}
main().catch(() => {
console.error('Check gateway and runtime credential settings');
process.exitCode = 1;
});proxyConnect сохраняет ответ на CONNECT отдельно от HTTPS-ответа. Поэтому отказ шлюза не называется ошибкой API. Даже после открытия туннеля назначение должно пройти проверку сертификата и вернуть подходящее содержимое. Равный IP в другом клиенте не заменяет эту проверку маршрута.
Сохраните лимиты и завершение ресурса
Axios ограничивает ожидание десятью секундами, общий AbortController — двадцатью. Сигнал получает и агент, включая ожидание ответа CONNECT. finally отменяет принадлежащее проверке соединение и уничтожает агент. Это бюджеты примера, а не точная гарантия прошедшего времени при любой нагрузке.
Буфер ответа ограничен 64 КиБ, тело запроса не отправляется, перенаправления не выполняются. Лимит ответа не равен списанному трафику: остаются протокольные расходы и буферизация. Для полезной загрузки другого размера задавайте ограничения осознанно и считайте попытки, а не только удачные результаты.
Проверка сертификата включена. В управляемой среде допустимый дополнительный CA задаётся штатным способом до запуска Node.js. Не отключайте проверку TLS для исправления 407 или CONNECT: эти события происходят на другом этапе.
Выберите действие по этапу ошибки
| Наблюдение | Следующая проверка |
|---|---|
| CONNECT 407 | Полный логин, пароль и ГБ по диагностике авторизации. |
| CONNECT 502 или 503 | Шлюз не открыл туннель; сохранить время и разобрать отказ CONNECT. |
| HTTP 403 или 429 назначения | Проверить правила доступа или ограничение сервиса; смена пароля шлюза их не исправляет. |
| ECONNABORTED или deadline exceeded | Установить, где закончился бюджет: соединение, заголовки или чтение. |
| Некорректный JSON или размер | Сравнить фактическое содержимое с ожидаемой небольшой проверкой. |
Переносите настройку в реальный клиент
Если проверка проходит, сделайте один разрешённый запрос рабочим клиентом. Для службы выделите клиент под стабильную конфигурацию и ограничьте очередь: уничтожение одноразового агента не должно отменять чужие задачи. Проверка curl и приложения помогает найти различие процессов; Node fetch имеет отдельный рецепт.
Мобильный и резидентский трафик Portproof используют общий баланс ГБ. Ни агент, ни его keepAlive не резервируют устройство и не гарантируют постоянный IP. Посмотрите актуальные тарифы, если нужна покупка; кабинет и checkout остаются на английском. Документация проверена 31 октября 2026 года, код сохранён из существующего английского руководства; нового теста живого пула, скорости или географии не заявлено.
Допустимое использование
Используйте прокси для разрешённых задач и соблюдайте правила принимающего сервиса. Настройка соединения не даёт права на доступ. Применяются правила допустимого использования · English.