Konfiguracja proxy w Node.js: Axios, Fetch, Undici i rotacja

Opcja proxy w axios to pułapka dla celów HTTPS, a natywny fetch całkowicie ignoruje zmienne środowiskowe proxy. Oto konfiguracja, która działa w axios, fetch i undici — agenci, autoryzacja, SOCKS5, rotacja i streaming.

Przekierowanie żądań Node.js przez proxy wydaje się być jednowierszowe, a zamienia się w popołudnie debugowania. Powodem jest to, że trzy klienci HTTP, których używa większość projektów — axios, natywny fetch, który pojawił się jako globalny w Node 18, i biblioteka undici — każdy z nich przyjmuje proxy inaczej i żaden nie zachowuje się tak, jak się spodziewasz. Axios ma wbudowaną konfigurację proxy, która jest udokumentowana, działa tylko w Node i cicho nie działa dla celów HTTPS za HTTP proxy: błąd, który jest otwarty na trackerze GitHub axios od 2020 roku i spowodował mocno głosowany wątek na Stack Overflow. Tymczasem natywny fetch ignoruje zmienne środowiskowe HTTP_PROXY i nie ma w ogóle opcji proxy. Ten przewodnik przedstawia konfigurację, która faktycznie działa w każdym kliencie, plus autoryzację, SOCKS5, rotację i streaming.

Konfiguracja proxy w Axios vs agenci proxy

Axios dostarcza obiekt proxy{ host, port, auth } — i działa dobrze dla celów HTTP. Pułapka to HTTPS: gdy celem jest https://, a proxy mówi HTTP, axios nie otwiera tunelu CONNECT i twoje żądanie albo zawiesza się, albo wraca z twoim prawdziwym IP. Rozwiązaniem, na które społeczność się zdecydowała, jest całkowite pominięcie wbudowanej konfiguracji i przekazanie axios agentowi proxy, a następnie ustawienie proxy: false, aby te dwa mechanizmy się nie kłóciły:

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>" }

Dwa szczegóły oszczędzają godziny. Po pierwsze, użyj zdestrukturyzowanego importu { HttpsProxyAgent } — w nowszych wersjach eksportowany jest jako symbol nazwany, a domyślny import daje obiekt, który rzuca wyjątek podczas konstrukcji. Po drugie, schemat URL proxy pozostaje http://, nawet gdy proxy przenosi ruch HTTPS: schemat opisuje, jak dotrzeć do proxy, a TLS do celu działa wewnątrz tunelu. Ten sam rodzaj błędu pojawia się w Pythonie; jeśli również pracujesz w requests, wzorce rymują się z naszym przewodnikiem naprawy ProxyError i SSLError.

Autoryzacja i zmienne środowiskowe

Autoryzowane proxy używają poświadczeń HTTP Basic. Z agentem, osadź je w URL jako http://user:pass@host:port; jeśli hasło zawiera @, : lub /, zakoduj je w URL za pomocą encodeURIComponent() najpierw, inaczej URL zostanie podzielony w złym miejscu. 407 Proxy Authentication Required oznacza, że poświadczenia zostały odrzucone lub twoje źródłowe IP nie jest na białej liście. Axios również czyta HTTP_PROXY, HTTPS_PROXY i NO_PROXY ze środowiska — przydatne do proxyzowania biblioteki zewnętrznej bez dotykania jej kodu — i wyłączasz to, ustawiając proxy: false. Ważne ostrzeżenie: natywny fetch nie czyta tych zmiennych, więc scraper, który polega na proxyzowaniu przez zmienne środowiskowe, idzie bezpośrednio w momencie, gdy przełączasz się z axios na fetch.

Porównanie jak axios, natywny fetch i undici akceptują proxy w Node.js, pokazujące agentów proxy w porównaniu do dyspozytora undici
To samo żądanie, trzy systemy hydrauliczne. Axios chce agenta, natywny fetch chce dyspozytora undici, a ich mieszanie to główna przyczyna 'proxy nie działa'.

Proxyzowanie natywnego fetch za pomocą undici

Globalny fetch w Node jest zbudowany na undici, a undici to miejsce, gdzie żyje proxy. Tworzysz ProxyAgent i przekazujesz go jako niestandardową opcję dispatcher — to nowoczesny, lekki sposób na proxyzowanie fetch, i obsługuje HTTPS CONNECT poprawnie od razu po wyjęciu z pudełka:

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());

Jeśli używasz undici bezpośrednio zamiast globalnego fetch, ten sam ProxyAgent podłącza się do request() lub do setGlobalDispatcher(), aby proxyzować każdy fetch w procesie naraz. To globalne przełączanie jednym wywołaniem to najczystszy sposób na przekierowanie całej bazy kodu przez proxy bez przekazywania dyspozytora przez każdą funkcję.

SOCKS5 proxy w Node.js

Ani axios, ani undici nie obsługują SOCKS natywnie — przekazanie ciągu socks5:// do konfiguracji proxy w axios skutkuje asercją protocol mismatch. Zainstaluj socks-proxy-agent i użyj go w ten sam sposób, co agenta HTTPS, podłączając do httpAgent i httpsAgent. Preferuj socks5h:// nad socks5://: końcowe h rozwiązuje DNS po stronie proxy, co zapobiega wyciekom DNS i rozwiązuje nazwy hostów z ograniczeniami geograficznymi z lokalizacji wyjściowej. Każdy plan proxy SOCKS5 udostępnia to samo bramę przez HTTP i SOCKS5, więc to tylko zmiana schematu, a nie nowy zakup:

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);

Rotacja bez listy proxy

Stara receptura — tablica IP, Math.random() na żądanie, usuwanie martwych — to kod, którego już nie utrzymujesz. Rotacyjna brama przypisuje świeże IP wyjściowe po stronie serwera przy każdym żądaniu, więc jeden punkt końcowy zachowuje się jak cała pula. Poprzez rotacyjne proxy rezydencjalne ta pula obejmuje ponad 90 milionów IP w ponad 200 krajach, a poniższa pętla drukuje różne pochodzenie przy każdej iteracji bez logiki rotacji:

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
}

Gdy przepływ obejmuje kilka żądań — logowanie, dodanie do koszyka, realizacja zamówienia — rotacja na żądanie przerywa sesję. Parametr sesji lepkiej w nazwie użytkownika proxy przypina jedno IP wyjściowe na określony czas, a następnie rotuje; ten sam punkt końcowy, jedna zmiana ciągu. Jeśli skalujesz to do tysięcy równoczesnych żądań, przenieś pracę poza pętle axios i przeczytaj nasz przewodnik po architekturze skrobania na dużą skalę dla kolejkowania i budżetów współbieżności.

Streaming odpowiedzi przez proxy

Pobieranie plików lub dużych ładunków JSON działa tak samo jak każde żądanie po podłączeniu agenta — ustaw responseType: "stream" i przekieruj ciało na dysk. Proxy obsługuje transfer przejrzyście, więc eksport 200MB nigdy nie buforuje się w pamięci:

import fs from "node:fs";

const r = await client.get("https://example.com/large.json", {
  responseType: "stream",
});
r.data.pipe(fs.createWriteStream("out.json"));
Lista kontrolna kontrastująca działające konfiguracje proxy w Node.js z powszechnymi błędami, które psują konfiguracje axios, fetch i SOCKS5
Większość awarii proxy w Node.js sprowadza się do pięciu błędów: błąd HTTPS w axios, domyślny import agenta, podwójna konfiguracja proxy, zły schemat SOCKS lub oczekiwanie, że fetch przeczyta zmienne środowiskowe.

Najczęściej zadawane pytania

Dlaczego mój proxy w axios nie działa?

Najczęstszą przyczyną jest cel HTTPS za HTTP proxy: wbudowana konfiguracja proxy w axios nie otwiera tunelu CONNECT i zwraca twoje prawdziwe IP lub zawiesza się. Przełącz się na agenta proxy — podłącz HttpsProxyAgent do httpAgent i httpsAgent, i ustaw proxy: false, aby axios przestał próbować obsługiwać proxy samodzielnie.

Czy axios obsługuje proxy SOCKS5?

Nie natywnie — przekazanie URL socks5:// do konfiguracji proxy powoduje błąd niezgodności protokołów. Zainstaluj socks-proxy-agent, zbuduj SocksProxyAgent i podłącz go do httpAgent i httpsAgent. Użyj schematu socks5h://, aby DNS rozwiązywał się po stronie proxy, a nie wyciekał z twojego komputera.

Jak używać proxy z natywnym fetch w Node.js?

Natywny fetch nie ma opcji proxy i ignoruje zmienne środowiskowe HTTP_PROXY. Utwórz ProxyAgent undici i przekaż go jako opcję dispatcher w wywołaniu fetch, lub wywołaj setGlobalDispatcher() raz, aby proxyzować każdy fetch w procesie. Undici obsługuje HTTPS CONNECT poprawnie bez dodatkowej konfiguracji.

Jak ustawić proxy w axios za pomocą zmiennych środowiskowych?

Eksportuj HTTP_PROXY, HTTPS_PROXY i opcjonalnie NO_PROXY z pełnymi URL proxy; axios czyta je automatycznie. Ustaw proxy: false na żądaniu lub instancji, aby axios ignorował środowisko. Pamiętaj, że to dotyczy tylko axios — undici i natywny fetch nie pobiorą tych zmiennych.

Cała historia mieści się na karcie: axios potrzebuje agenta i proxy: false, natywny fetch potrzebuje dyspozytora undici, SOCKS potrzebuje własnego agenta, a rotacja należy do bramy, a nie do twojej pętli. Prawidłowo skonfiguruj hydraulikę, a ostatnią zmienną jest jakość IP — czyste wyjście rezydencjalne przechodzi tam, gdzie oznaczone IP z centrum danych dostaje 403 na tym samym kodzie.

Zdobądź proxy rezydencjalne, które przechodzą przy pierwszym żądaniu