Configuration de proxy Node.js : Axios, Fetch, Undici & Rotation

L'option proxy d'axios est un piège pour les cibles HTTPS, et le fetch natif ignore complètement vos variables d'environnement de proxy. Voici la configuration qui fonctionne avec axios, fetch et undici — agents, authentification, SOCKS5, rotation et streaming.

Acheminer les requêtes Node.js à travers un proxy semble être une ligne de code et se transforme en une après-midi de débogage. La raison est que les trois clients HTTP les plus utilisés dans les projets — axios, le fetch natif livré en tant que global dans Node 18, et la bibliothèque sous-jacente undici — prennent chacun un proxy différemment, et aucun ne se comporte comme vous l'attendez. Axios a une configuration proxy intégrée qui est documentée, uniquement pour Node, et discrètement cassée pour les cibles HTTPS derrière un proxy HTTP : un bug ouvert sur le tracker GitHub d'axios depuis 2020 qui a alimenté un fil très voté sur Stack Overflow. Fetch natif, quant à lui, ignore les variables d'environnement HTTP_PROXY et n'a pas d'option de proxy du tout. Ce guide vous donne la configuration qui fonctionne réellement dans chaque client, plus l'authentification, SOCKS5, la rotation et le streaming.

Configuration du proxy axios vs agents de proxy

Axios est livré avec un objet proxy{ host, port, auth } — et cela fonctionne bien pour les cibles HTTP simples. Le piège est HTTPS : lorsque la cible est https:// et que le proxy parle HTTP, axios échoue à ouvrir le tunnel CONNECT et votre requête soit se bloque, soit revient avec votre véritable IP. La solution sur laquelle la communauté s'est mise d'accord est de contourner entièrement la configuration intégrée et de fournir à axios un agent de proxy à la place, puis de définir proxy: false pour que les deux mécanismes ne se battent pas :

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

Deux détails vous font gagner des heures. Premièrement, utilisez l'importation déstructurée { HttpsProxyAgent } — les versions récentes l'exportent comme un symbole nommé, et une importation par défaut vous donne un objet qui génère une erreur lors de sa construction. Deuxièmement, le schéma d'URL du proxy reste http:// même lorsque le proxy transporte du trafic HTTPS : le schéma décrit comment vous atteignez le proxy, et le TLS vers la cible s'exécute à l'intérieur du tunnel. La même classe d'échec apparaît en Python ; si vous travaillez également avec requests, les modèles riment avec notre guide de correction ProxyError et SSLError.

Authentification et variables d'environnement

Les proxies authentifiés utilisent les identifiants HTTP Basic. Avec un agent, intégrez-les dans l'URL comme http://user:pass@host:port ; si le mot de passe contient @, : ou /, encodez-le avec encodeURIComponent() d'abord ou l'URL se divise au mauvais endroit. Un 407 Proxy Authentication Required signifie que les identifiants ont été rejetés ou que votre IP source n'est pas sur liste blanche. Axios lit également HTTP_PROXY, HTTPS_PROXY et NO_PROXY depuis l'environnement — pratique pour proxy une bibliothèque tierce sans toucher à son code — et vous désactivez cela en définissant proxy: false. L'avertissement important : le fetch natif ne lit pas ces variables, donc un scraper qui repose sur le proxying par variables d'environnement passe silencieusement en direct dès que vous passez d'axios à fetch.

Comparaison de la manière dont axios, fetch natif et undici acceptent chacun un proxy dans Node.js, montrant les agents de proxy par rapport au dispatcher undici
Même requête, trois systèmes de plomberie. Axios veut un agent, fetch natif veut un dispatcher undici, et les mélanger est la cause numéro un du 'proxy ne fonctionne pas'.

Proxying fetch natif avec undici

Le fetch global de Node est construit sur undici, et undici est là où le proxy réside. Vous créez un ProxyAgent et le passez comme option non standard dispatcher — c'est la manière moderne et légère en dépendances de proxy fetch, et il gère correctement le CONNECT HTTPS dès le départ :

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

Si vous êtes directement sur undici plutôt que sur fetch global, le même ProxyAgent se branche dans request() ou dans setGlobalDispatcher() pour proxy chaque fetch dans le processus en une fois. Ce commutateur global à appel unique est la manière la plus propre de router une base de code entière à travers un proxy sans passer un dispatcher à travers chaque fonction.

Proxies SOCKS5 dans Node.js

Ni axios ni undici ne parlent SOCKS nativement — passez une chaîne socks5:// à la configuration proxy d'axios et vous obtenez une assertion protocol mismatch. Installez socks-proxy-agent et utilisez-le de la même manière que l'agent HTTPS, branché à la fois dans httpAgent et httpsAgent. Préférez socks5h:// à socks5:// : le h final résout le DNS côté proxy, ce qui empêche les fuites DNS et résout les noms d'hôte géo-clôturés depuis l'emplacement de sortie. Chaque plan de proxy SOCKS5 expose la même passerelle sur HTTP et SOCKS5, donc c'est un échange de schéma, pas un nouvel achat :

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

Rotation sans liste de proxies

La vieille recette — un tableau d'IPs, Math.random() par requête, élaguer les mortes — est un code que vous ne maintenez plus. Une passerelle rotative attribue une nouvelle IP de sortie côté serveur à chaque requête, donc un point de terminaison se comporte comme une piscine entière. À travers les proxies résidentiels rotatifs, cette piscine s'étend sur plus de 90 millions d'IPs dans plus de 200 pays, et la boucle ci-dessous imprime une origine différente à chaque itération sans logique de rotation :

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
}

Lorsqu'un flux s'étend sur plusieurs requêtes — connexion, ajout au panier, paiement — la rotation par requête casse la session. Un paramètre de session collante dans le nom d'utilisateur du proxy fixe une IP de sortie pour une fenêtre définie, puis tourne ; même point de terminaison, un changement de chaîne. Si vous évoluez cela en milliers de requêtes simultanées, déplacez le travail hors des boucles axios et lisez notre guide sur l'architecture de scraping à grande échelle pour les files d'attente et les budgets de concurrence.

Streaming des réponses à travers un proxy

Le téléchargement de fichiers ou de grandes charges utiles JSON fonctionne de la même manière que toute requête une fois l'agent attaché — définissez responseType: "stream" et redirigez le corps vers le disque. Le proxy gère le transfert de manière transparente, donc une exportation de 200 Mo ne se met jamais en mémoire tampon :

import fs from "node:fs";

const r = await client.get("https://example.com/large.json", {
  responseType: "stream",
});
r.data.pipe(fs.createWriteStream("out.json"));
Liste de contrôle contrastant les configurations de proxy Node.js fonctionnelles avec les erreurs courantes qui cassent les configurations axios, fetch et SOCKS5
La plupart des échecs de proxy Node.js se réduisent à cinq erreurs : le bug HTTPS d'axios, une importation d'agent par défaut, une configuration de proxy doublée, un schéma SOCKS incorrect, ou s'attendre à ce que fetch lise les variables d'environnement.

Questions fréquemment posées

Pourquoi mon proxy axios ne fonctionne-t-il pas ?

La cause la plus courante est une cible HTTPS derrière un proxy HTTP : la configuration proxy intégrée d'axios échoue à ouvrir le tunnel CONNECT et renvoie votre véritable IP ou se bloque. Passez à un agent de proxy — attachez HttpsProxyAgent à httpAgent et httpsAgent, et définissez proxy: false pour qu'axios cesse d'essayer de gérer le proxy lui-même.

Axios prend-il en charge les proxies SOCKS5 ?

Pas nativement — passer une URL socks5:// à la configuration proxy génère une erreur de non-concordance de protocole. Installez socks-proxy-agent, construisez un SocksProxyAgent, et branchez-le à la fois dans httpAgent et httpsAgent. Utilisez le schéma socks5h:// pour que le DNS soit résolu côté proxy plutôt que de fuir depuis votre machine.

Comment utiliser un proxy avec le fetch natif dans Node.js ?

Fetch natif n'a pas d'option de proxy et ignore les variables d'environnement HTTP_PROXY. Créez un ProxyAgent undici et passez-le comme option dispatcher sur l'appel fetch, ou appelez setGlobalDispatcher() une fois pour proxy chaque fetch dans le processus. Undici gère correctement le CONNECT HTTPS sans configuration supplémentaire.

Comment configurer un proxy axios avec des variables d'environnement ?

Exportez HTTP_PROXY, HTTPS_PROXY et éventuellement NO_PROXY avec des URLs de proxy complètes ; axios les lit automatiquement. Définissez proxy: false sur une requête ou une instance pour qu'axios ignore l'environnement. Rappelez-vous que cela n'affecte qu'axios — undici et fetch natif ne prendront pas ces variables en compte.

Toute l'histoire tient sur une carte : axios a besoin d'un agent et proxy: false, fetch natif a besoin d'un dispatcher undici, SOCKS a besoin de son propre agent, et la rotation appartient à la passerelle plutôt qu'à votre boucle. Obtenez la plomberie correcte et la dernière variable est la qualité de l'IP — une sortie résidentielle propre passe là où une IP de centre de données signalée obtient un 403 sur le même code.

Obtenez des proxies résidentiels qui passent dès la première requête