Retour au blog
Guides
Mihnea-Octavian ManolacheLast updated on May 1, 202613 min read

Comment utiliser un proxy dans Node-Fetch : Un guide pratique

Comment utiliser un proxy dans Node-Fetch : Un guide pratique
En bref : Node-Fetch ne dispose pas d'un commutateur de proxy intégré ; vous devez donc intégrer un agent HTTP, HTTPS ou SOCKS5 à la requête via son agent option. Ce guide explique en détail comment utiliser un proxy dans Node-Fetch de bout en bout : proxys HTTP et HTTPS authentifiés, SOCKS5, rotation, tentatives de reconnexion, cas limites TLS, dépannage et la nouvelle approche undici pour le fetch natif de Node 18+.

Si vous vous êtes déjà retrouvé face à une erreur 403 provenant d'une cible que vous parveniez auparavant à scraper sans problème, vous comprenez déjà pourquoi cet article existe. Apprendre à utiliser un proxy dans Node-Fetch, c'est la différence entre un script qui fonctionne sur votre ordinateur portable et un script qui survit en CI sur une autre adresse IP, dans un autre pays, face à une véritable pile anti-bot. La bonne nouvelle : l'utilisation d'un proxy dans Node-Fetch se résume à une petite interface API, le reste n'étant que de la « colle opérationnelle ».

Node-Fetch est un client HTTP populaire pour Node.js qui transpose le window.fetch au serveur. Il est compact, asynchrone et agréable à utiliser, mais il ne propose délibérément pas d’ proxy option. À la place, il expose un agent emplacement, dans lequel vous pouvez intégrer un agent proxy externe. Ce choix de conception unique est le mécanisme à la base de toutes les recettes ci-dessous.

Ce guide est indépendant du fournisseur et axé sur le code. Vous allez configurer un proxy HTTP/HTTPS, envoyer votre première requête via le proxy, ajouter des identifiants en toute sécurité, passer à SOCKS5, faire tourner un pool, ajouter des délais d'attente et des tentatives de reconnexion, et vérifier que le trafic passe bien par le proxy. Nous aborderons également l'alternative Node 18+ utilisant ProxyAgent, ainsi qu'une matrice de dépannage pour les erreurs que vous rencontrerez dès le premier jour.

Comment utiliser un proxy dans Node-Fetch : pourquoi vous avez besoin d'un agent

Node-Fetch ne dispose pas de paramètre de proxy intégré. Pour acheminer les requêtes via un proxy, vous devez passer un http.Agent (ou https.Agent) à l' agent option sur chaque fetch() appel. Les paquets communautaires https-proxy-agent et socks-proxy-agent implémentent cette interface et acheminent votre trafic via le proxy que vous leur indiquez.

En résumé : la seule connaissance spécifique à Node-Fetch dont vous avez besoin est que l' agent option existe et accepte tout agent compatible. Tout le reste (HTTP, HTTPS, SOCKS5, authentification, particularités TLS, rotation) se trouve au niveau de la couche agent. Cela permet de conserver un code de récupération identique quel que soit le fournisseur et de changer de transport sans réécrire la logique métier.

Configuration du projet et dépendances

Vous avez besoin d'une version LTS récente de Node.js. Le node-fetch README indique une version minimale précise qui a évolué au fil des versions, vérifiez-la donc par rapport au node-fetch avant de verrouiller votre matrice CI. Tout ce qui se trouve sur une ligne LTS actuelle est normalement sans risque.

Choisissez node-fetch version majeure de manière réfléchie. La version 3 est réservée à ESM, ce qui signifie que vous devez définir "type": "module" dans votre package.json (ou utilisez .mjs fichiers) et la chargez avec import. La version 2 fonctionne toujours dans les projets CommonJS et est interchangeable à des fins de proxy. Les deux versions se comportent de manière très similaire, la v2 est donc un choix tout à fait raisonnable si votre base de code n'est pas encore en ESM.

Installez l'agent proxy en même temps que Node-Fetch :

# CommonJS friendly
npm install node-fetch@2 https-proxy-agent

# ESM (requires "type": "module" in package.json)
npm install node-fetch https-proxy-agent

Envoyer la première requête via un proxy HTTP

Une fois les paquets installés, la procédure est mécanique : construisez une URL de proxy, transmettez-la à HttpsProxyAgent, puis transmettez cet agent à fetch(). La même classe d'agent fonctionne que votre cible soit http:// ou https://, car elle achemine le trafic HTTPS via le proxy avec CONNECT.

// proxy-fetch.js (CommonJS, node-fetch v2)
const fetch = require('node-fetch');
const { HttpsProxyAgent } = require('https-proxy-agent');

async function main() {
  const proxyUrl = `http://${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
  const agent = new HttpsProxyAgent(proxyUrl);

  const res = await fetch('https://ifconfig.me/all.json', { agent });
  const body = await res.json();
  console.log('Outbound IP:', body.ip_addr);
}

main().catch(console.error);

Quelques détails qui ont leur importance lorsque vous déployez cette solution :

  • Utilisez une importation déstructurée ({ HttpsProxyAgent }) pour https-proxy-agent v6 et versions ultérieures. La structure d'exportation par défaut a changé d'une version majeure à l'autre, et une importation incorrecte est une cause fréquente de undefined is not a constructor.
  • Réutilisez l'agent pour toutes les requêtes ciblant le même proxy. Créer un nouvel agent à chaque appel fonctionne, mais vous perdez le pool de connexions et payez un handshake TLS à chaque fois.
  • Accédez d'abord à un point de terminaison IP-echo connu (ifconfig.me, ident.me, ou ipinfo.io/json). Si vous ne voyez pas l'adresse IP du proxy revenir, ne passez pas à l'étape suivante ; rien d'autre ne fonctionnera tant que ce cas de base n'aura pas abouti.

Authentification auprès d'un serveur proxy

La plupart des proxys payants exigent des identifiants. La convention consiste à les placer dans l'URL avec le http://USERNAME:PASSWORD@HOST:PORT , ce que https-proxy-agent effectue l'analyse pour vous :

const user = encodeURIComponent(process.env.PROXY_USER);
const pass = encodeURIComponent(process.env.PROXY_PASS);
const proxyUrl = `http://${user}:${pass}@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
const agent = new HttpsProxyAgent(proxyUrl);

Deux choses posent problème ici. Premièrement, le codage en dur des identifiants dans les fichiers source les divulgue via l'historique Git ; conservez-les dans des variables d'environnement (ou un gestionnaire de secrets) et injectez-les au moment de l'exécution. Deuxièmement, les caractères spéciaux dans les mots de passe (@, :, /, #) corrompent silencieusement l'analyse de l'URL, ce qui entraîne une 407 Proxy Authentication Required au lieu d'une erreur d'analyse. En encapsulant le nom d'utilisateur et le mot de passe dans encodeURIComponent() élimine toute cette catégorie de bogues.

Utilisation de proxys SOCKS5 avec Node-Fetch

Lorsque votre fournisseur vous fournit un point de terminaison SOCKS5, remplacez l'agent. Node-Fetch ne se soucie pas du protocole ; il appelle simplement l'agent que vous lui fournissez. Installez socks-proxy-agent:

npm install socks-proxy-agent
const fetch = require('node-fetch');
const { SocksProxyAgent } = require('socks-proxy-agent');

// socks5h:// resolves DNS through the proxy; socks5:// resolves locally.
const proxyUrl = `socks5h://${process.env.PROXY_USER}:${process.env.PROXY_PASS}` +
                 `@${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`;
const agent = new SocksProxyAgent(proxyUrl);

fetch('https://ifconfig.me/all.json', { agent })
  .then(r => r.json())
  .then(console.log);

Préférez le socks5h:// schéma lorsque vous effectuez un scraping, car il transfère la résolution DNS via le proxy. Le schéma socks5:// résout le nom d’hôte sur votre machine, ce qui divulgue votre DNS réel et va en partie à l’encontre de l’intérêt initial du routage via le proxy.

Utilisation de cibles HTTPS et de certificats auto-signés

Certains produits proxy, en particulier les services de « déblocage Web » de type interception, présentent leur propre certificat TLS à votre client et resignent la réponse en amont. Node rejettera cette poignée de main par défaut avec UNABLE_TO_VERIFY_LEAF_SIGNATURE ou SELF_SIGNED_CERT_IN_CHAIN.

La solution de facilité consiste à définir process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'. Ne faites pas cela en production. Cela désactive la vérification des certificats pour toutes les requêtes sortantes du processus, y compris celles que vous souhaitez absolument voir vérifiées.

Limitez plutôt cette option à l'agent lui-même :

const agent = new HttpsProxyAgent(proxyUrl, { rejectUnauthorized: false });

Cela permet de préserver l'intégrité de la configuration TLS du reste de votre application. Le nom exact de l'option du constructeur et son mode de propagation ont changé au fil des https-proxy-agent versions majeures ; vérifiez donc à nouveau la page npm du paquet lors de la mise à jour, et évitez complètement ce drapeau si vous pouvez plutôt épingler un ensemble de certificats CA.

Rotation des proxys pour un scraping résilient

De nombreux sites utilisent la limitation de débit basée sur l'IP et la détection des bots, de sorte qu'une seule adresse IP de proxy sera bridée ou bannie dès que vous augmenterez votre échelle. La rotation au sein d'un pool répartit la charge et donne l'impression que chaque requête provient d'un utilisateur différent. Il existe deux modèles à connaître pour utiliser un proxy dans Node-Fetch à grande échelle : un choix aléatoire par requête et un tour de rôle déterministe. Les deux s'appuient sur le même principe d'un agent par proxy que vous connaissez déjà.

Choisir un proxy aléatoire à chaque requête

Lorsque la seule chose qui vous importe est la dispersion, effectuez un indexage aléatoire dans le pool et instanciez un nouvel agent par appel :

const proxies = process.env.PROXY_POOL.split(','); // host:port,host:port,...

function randomAgent() {
  const pick = proxies[Math.floor(Math.random() * proxies.length)];
  return new HttpsProxyAgent(`http://${pick}`);
}

await fetch(targetUrl, { agent: randomAgent() });

Si le même proxy traite plusieurs requêtes consécutives, mettez son agent en cache dans un Map indexé par l'URL du proxy afin de réutiliser la connexion.

Itération séquentielle à travers une liste de proxys

Pour un débogage reproductible ou un simple comportement de rotation, parcourez la liste à l'aide d'un compteur. La rotation séquentielle facilite également l'attribution des métriques de réussite par proxy, ce qui est important lorsque vous commencez à retirer les proxys inactifs :

let i = 0;
for (const url of urls) {
  const agent = new HttpsProxyAgent(`http://${proxies[i % proxies.length]}`);
  await fetch(url, { agent });
  i++;
}

Ajout de tentatives de réessai, de délais d'expiration et de gestion des erreurs

Le trafic de production via des proxys publics échoue de manière intéressante : blocages, sockets à demi-ouverts, ECONNRESET, tempêtes soudaines de 5xx. Une configuration robuste combine un délai d'expiration par requête, une boucle de réessais limitée avec recul, et un disjoncteur qui retire un proxy après des échecs répétés. (Pour en savoir plus sur la stratégie de rotation, consultez notre guide approfondi sur la rotation des proxys pour le web scraping.)

async function fetchWithProxy(url, getAgent, opts = {}) {
  const { tries = 3, timeoutMs = 10_000 } = opts;
  let lastErr;

  for (let attempt = 1; attempt <= tries; attempt++) {
    const ctrl = new AbortController();
    const t = setTimeout(() => ctrl.abort(), timeoutMs);
    try {
      const res = await fetch(url, { agent: getAgent(), signal: ctrl.signal });
      if (res.ok) return res;
      if (res.status === 407 || res.status === 403) throw new Error(`status ${res.status}`);
    } catch (err) {
      lastErr = err;
      const backoff = 2 ** attempt * 250 + Math.random() * 250;
      await new Promise(r => setTimeout(r, backoff));
    } finally {
      clearTimeout(t);
    }
  }
  throw lastErr ?? new Error('exhausted retries');
}

Suivez le nombre d'échecs par URL de proxy dans un petit objet, et lorsqu'un proxy dépasse un seuil (trois échecs en une minute, par exemple), retirez-le du pool jusqu'à ce qu'un délai de refroidissement soit écoulé. Cette règle unique est la partie que la plupart des tutoriels omettent lorsqu'ils expliquent comment utiliser un proxy dans Node-Fetch, et c'est ce qui empêche une poignée d'adresses IP inactives de contaminer chaque nouvelle tentative. Associez-la à l'AbortControllere afin qu'un proxy bloqué ne bloque jamais votre worker indéfiniment.

Vérifier que le proxy est bien utilisé

Ne faites jamais confiance à un proxy que vous n'avez pas vérifié. Le test le plus simple consiste à effectuer une comparaison : interrogez deux fois un point de terminaison IP/géographique, une fois avec l'agent et une fois sans, puis comparez les résultats. L'adresse IP et le pays doivent changer.

const direct = await fetch('https://ipinfo.io/json').then(r => r.json());
const proxied = await fetch('https://ipinfo.io/json', { agent }).then(r => r.json());
console.log('direct  :', direct.ip, direct.country);
console.log('proxied :', proxied.ip, proxied.country);

Si les deux lignes correspondent, votre agent est ignoré, généralement à cause d'une erreur de format d'importation ou d'une clé d'option mal orthographiée. Ajoutez cette vérification à la sonde de démarrage de votre scraper afin qu'un déploiement silencieusement direct échoue de manière évidente.

Récupération native dans Node 18+ vs Node-Fetch

Node 18 intègre un fetch alimenté par undici, et de nombreuses équipes ont complètement abandonné le node-fetch . Le hic : la fonction intégrée fetch n'accepte pas l'option agent option, donc https-proxy-agent ne s'intégrera pas directement. L'équivalent natif est ProxyAgent, défini comme répartiteur global :

import { ProxyAgent, setGlobalDispatcher } from 'undici';

setGlobalDispatcher(new ProxyAgent(process.env.PROXY_URL));

const res = await fetch('https://ifconfig.me/all.json');
console.log(await res.json());

L'API du proxy undici a évolué au fil des versions (authentification dans l'URL, en-têtes personnalisés, dispacheurs au niveau de la requête), donc consultez la documentation actuelle d'undici avant de vous engager. Le modèle mental correspond toujours parfaitement à la manière d'utiliser un proxy dans Node-Fetch, mais au niveau de la couche de dispatching plutôt qu'au niveau de chaque requête.

Dépannage des erreurs courantes du proxy Node-Fetch

La plupart des node-fetch bugs de proxy se résument à une petite matrice :

Symptôme

Cause probable

Solution

ECONNREFUSED

Hôte ou port proxy incorrect, ou le proxy est hors service.

Telnet/nc l'hôte:port ; basculez vers un autre proxy.

ETIMEDOUT / requête bloquée

Pas de AbortController délai, ou le proxy rejette silencieusement des paquets.

Enveloppez chaque récupération d'un délai d'expiration par requête et réessayez sur un autre proxy.

407 Proxy Authentication Required

Identifiants manquants ou URL corrompue.

Encodez l'utilisateur/le mot de passe en URL ; vérifiez que les variables d'environnement sont chargées.

SELF_SIGNED_CERT_IN_CHAIN

Le proxy présente son propre certificat TLS.

Définissez rejectUnauthorized: false sur l'agent (portée), et non dans la variable d'environnement globale.

Cannot find module 'node-fetch'

ESM v3 importé depuis un fichier CommonJS.

Ajouter "type": "module" ou revenir à node-fetch@2.

HttpsProxyAgent is not a constructor

Format d'importation incorrect pour v6+.

Utilisation const { HttpsProxyAgent } = require('https-proxy-agent').

Lorsqu'une cible continue d'échouer sur plusieurs proxys en bon état, le goulot d'étranglement réside généralement dans la détection anti-bot plutôt que dans la couche proxy. À ce stade, aucun ajustement de l'utilisation d'un proxy dans Node-Fetch ne sera d'aucune aide ; vous avez besoin d'une couche de requête qui gère également la détection.

Points clés et prochaines étapes

Le mécanisme sous-jacent à l'utilisation d'un proxy dans Node-Fetch est une option parmi d'autres : agent. Choisissez la bonne classe d'agent (HttpsProxyAgent pour HTTP/HTTPS, SocksProxyAgent pour SOCKS5), fournissez-lui une URL correctement encodée, et le reste se résume à la rotation, aux tentatives de reconnexion et à la vérification. À partir de là, les prochaines étapes logiques consistent à superposer la logique de rotation et à comparer d'autres clients HTTP pour Node.js.

Points clés

  • Node-Fetch ne propose pas d' proxy option ; vous intégrez la prise en charge en passant un Agent (à partir de https-proxy-agent ou socks-proxy-agent) au agent champ sur fetch().
  • Choisissez la version majeure avec soin : node-fetch@3 est réservé à l'ESM et nécessite "type": "module", tandis que node-fetch@2 est le choix compatible avec CommonJS offrant le même comportement de proxy.
  • Encodez toujours les identifiants en URL et lisez-les à partir des variables d'environnement. Un 407 Proxy Authentication Required est plus souvent un bug d'analyse qu'un véritable échec d'authentification.
  • Le code de proxy Node-Fetch de niveau production combine AbortController des délais d'expiration, un recul exponentiel et l'abandon d'un proxy inactif après quelques échecs, et ne se limite pas à un simple try/catch autour de fetch.
  • Sur Node 18+ avec fetch, l' agent option ne fonctionne pas ; utilisez celle d'undici ProxyAgent plus setGlobalDispatcher et revérifiez l'interface API par rapport à la documentation actuelle d'undici.

FAQ

Node-Fetch v3 prend-il en charge les proxys de manière native ?

Non. Ni la v2 ni la v3 de Node-Fetch n'implémentent d' proxy option. Le mécanisme de proxy est identique dans les deux versions principales : installez https-proxy-agent (ou socks-proxy-agent), créez un agent à partir de l'URL de votre proxy, puis transmettez-le fetch() via le agent . La seule différence entre la v2 et la v3 réside dans le système de modules : ESM dans la v3 contre CommonJS dans la v2.

Puis-je réutiliser le même HttpsProxyAgent pour plusieurs appels fetch ?

Oui, et vous devriez le faire. La réutilisation d'un agent par paire (proxyUrl, hôte cible) permet au pool de sockets sous-jacent de maintenir les connexions actives, ce qui supprime une négociation TLS à chaque requête et réduit sensiblement la latence en cas de charge. Ne créez un nouvel agent que lorsque l'URL du proxy elle-même change, par exemple lors d'une rotation. Mettez-les en cache dans un Map clé correspondant à l'URL du proxy afin de permettre à la fois la réutilisation et la rotation.

Quelle est la différence entre HttpProxyAgent et HttpsProxyAgent, et quand dois-je utiliser l'un ou l'autre ?

HttpProxyAgent achemine les requêtes en clair http:// demandes via un proxy sans CONNECT. HttpsProxyAgent émettre de requête HTTP CONNECT vers le proxy, puis exécute TLS vers la cible, ce qui est nécessaire pour toute https:// URL. En pratique, HttpsProxyAgent couvre les deux protocoles en toute sécurité et constitue la recommandation par défaut. N'utilisez HttpProxyAgent uniquement lorsque vous avez une raison spécifique et que vous visez des points de terminaison HTTP uniquement.

Pourquoi ma requête Node-Fetch via le proxy renvoie-t-elle le code 407 « Proxy Authentication Required » ?

Un code 407 signifie que le proxy n’a pas accepté vos identifiants, mais la cause se situe généralement en amont du proxy lui-même. La cause la plus courante est un caractère spécial dans le mot de passe qui perturbe l’analyse de l’URL. Encadrez les deux champs entre encodeURIComponent et rechargez-les à partir de variables d'environnement. Vérifiez ensuite le format des identifiants attendu par votre fournisseur (certains exigent un jeton de session, un code pays ou un préfixe de session dans le nom d'utilisateur).

Comment utiliser un proxy avec la fonction fetch intégrée à Node.js 18+ au lieu de node-fetch ?

La fonction native fetch de Node 18+ utilise undici, qui ignore l'option agent option. Installez undici, créez une ProxyAgent à partir de l'URL de votre proxy, puis enregistrez-le avec setGlobalDispatcher. Par la suite, chaque fetch() passe par le proxy sans autre modification du code. L'API undici a évolué au fil des versions ; vérifiez donc les noms actuels des options dans la documentation d'undici avant de les fixer.

Conclusion

Une fois que vous avez assimilé l' agent option, chaque recette de ce guide n'est qu'une petite variation sur le même thème. HTTP, HTTPS et SOCKS5 partagent une signature de récupération ; l'authentification consiste en un encodage d'URL correctement effectué ; la rotation, les tentatives de reconnexion et le contournement des proxys inactifs sont gérés par un simple wrapper autour de fetch(); et la route undici pour Node 18+ est le même modèle mental transposé en un répartiteur global.

Ne sous-estimez pas la couche opérationnelle. Les proxys gratuits sont inutiles en production : une mauvaise réputation IP, des temps d'arrêt élevés et un comportement TLS imprévisible épuiseront votre budget d'erreurs. Un pool résidentiel ou de centre de données propre, associé à l'enveloppe de délai d'attente et de réessai mentionnée précédemment, est ce qui transforme un snippet en un scraper déployable.

Si vous préférez ne pas gérer vous-même l'infrastructure proxy, l'API Scraper de WebScrapingAPI gère la rotation des proxys, la protection anti-bot et les tentatives de reconnexion derrière un point de terminaison unique, ce qui vous permet de conserver votre node-fetch code et de changer la couche de requêtes. À partir de là, les prochaines étapes logiques consistent à mettre en place une stratégie de rotation et à choisir le client HTTP Node.js adapté à votre charge de travail, deux sujets que nos guides complémentaires traitent en détail.

À propos de l'auteur
Mihnea-Octavian Manolache, Développeur Full Stack @ WebScrapingAPI
Mihnea-Octavian ManolacheDéveloppeur Full Stack

Mihnea-Octavian Manolache est ingénieur Full Stack et DevOps chez WebScrapingAPI, où il développe des fonctionnalités pour les produits et assure la maintenance de l'infrastructure qui garantit le bon fonctionnement de la plateforme.

Commencez à créer

Prêt à faire évoluer votre système de collecte de données ?

Rejoignez plus de 2 000 entreprises qui utilisent WebScrapingAPI pour extraire des données Web à l'échelle de l'entreprise, sans aucun coût d'infrastructure.