Scraping

Comment configurer des proxys résidentiels dans Node.js avec Axios, Fetch et Got

Le câblage de l'agent tient en dix lignes. Configurer un projet Node pour que les proxys restent configurables, vérifiables et économiques, voilà ce qui prend le plus de temps. Un guide de configuration.

James Meadow

James Meadow

4 septembre 2026 · 10 min de lecture

Faire passer une seule requête à travers un proxy en Node est un problème à dix lignes. Tous les tutoriels s’arrêtent là, puis le projet grandit : un second client HTTP apparaît, des identifiants se retrouvent codés en dur dans trois fichiers, quelqu’un a besoin de l’Allemagne au lieu des États-Unis, et plus personne ne peut dire avec certitude si les requêtes partent réellement d’où elles sont censées partir.

Ceci est un guide de mise en place plutôt qu’un guide de syntaxe. Si ce qu’il vous faut est la configuration exacte de l’agent qu’attend chaque client, y compris la raison pour laquelle Axios a besoin de proxy: false en plus de son agent, cela est traité en détail dans utiliser des proxies résidentiels en Node.js avec Axios et Got. Ce qui suit explique comment organiser un projet pour que le câblage reste correct à mesure que le projet grandit.

Décidez quels clients vous supportez réellement

Node compte trois clients HTTP couramment utilisés, et ils gèrent les proxies via des mécanismes différents. Supporter les trois est normal dans une base de code d’un certain âge, mais cela devrait être une décision plutôt qu’un accident.

Axios a besoin d’un agent explicite, car sa propre option proxy ne gère pas le tunneling HTTPS comme on pourrait s’y attendre. Installez https-proxy-agent.

Got prend l’agent dans un emplacement agent.https plutôt que comme option de premier niveau.

Le fetch natif passe par undici, il a donc besoin de ProxyAgent comme dispatcher. Undici est fourni avec Node, mais vous voudrez l’ajouter comme dépendance explicite si vous construisez vous-même des dispatchers.

La conséquence pratique est que votre liste de dépendances est déterminée par les clients que vous conservez, donc garder deux clients signifie maintenir deux chemins de proxy. La plupart des bases de code auraient intérêt à se standardiser sur un seul et à convertir les retardataires, et celles qui ont vraiment besoin de deux devraient au moins savoir pourquoi.

Les identifiants appartiennent à l’environnement, pas au code source

La passerelle prend le ciblage dans le nom d’utilisateur, ce qui signifie que la chaîne d’identifiants et la configuration de routage sont une seule et même chaîne. C’est pratique, et c’est aussi ainsi que des identifiants de proxy finissent par être commités.

Gardez les éléments séparés dans la configuration :

PROXY_HOST=p.shifter.io
PROXY_PORT=443
PROXY_USER=customer-USERNAME
PROXY_PASS=your-password
PROXY_COUNTRY=us

Assemblez ensuite le nom d’utilisateur au moment de l’exécution. La règle qui vous évitera des problèmes plus tard est qu’aucun fichier en dehors de votre module de proxy ne devrait contenir une URL de proxy littérale. Une fois qu’une chaîne d’identifiants avec ciblage intégré apparaît en clair dans un scraper, elle est copiée, et les copies divergent.

Ne mettez pas le mot de passe dans une URL que vous journalisez. Les URL de proxy sont le moyen le plus courant par lequel des identifiants atteignent un agrégateur de logs, car la ligne de débogage naturelle est l’URL entière.

Un seul module construit les agents

La décision structurelle la plus importante est d’avoir exactement un seul endroit qui transforme la configuration en agent. C’est un petit module et il évite toute une catégorie de problèmes.

proxy.js
import { HttpsProxyAgent } from "https-proxy-agent";
const { PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS } = process.env;
export function proxyUrl({ country, session, ttl } = {}) {
const parts = [PROXY_USER];
if (country) parts.push("country", country);
if (session) parts.push("sid", session);
if (session && ttl) parts.push("ttl", String(ttl));
const user = parts.join("-");
return `https://${user}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}`;
}
export function agentFor(opts) {
return new HttpsProxyAgent(proxyUrl(opts));
}

Deux détails de cet extrait valent la peine d’être explicités. Les indicateurs de ciblage sont construits à partir d’options nommées plutôt qu’en concaténant des chaînes à chaque point d’appel, ce qui empêche une faute de frappe dans le nom d’un indicateur de se transformer en une erreur 407 qui ressemble à un problème d’identifiants. Et ttl n’est ajouté que lorsqu’une session est présente, car un délai de vie n’a rien à maintenir en vie sans identifiant de session.

Les appelants ne voient alors jamais d’URL :

const agent = agentFor({ country: "de", session: "job-141", ttl: 600 });
// axios
await axios.get(url, { httpsAgent: agent, proxy: false });
// got
await got(url, { agent: { https: agent } });

Le fetch natif est celui qui ne prend pas d’agent, puisque undici veut plutôt un dispatcher :

import { ProxyAgent, fetch } from "undici";
import { proxyUrl } from "./proxy.js";
const dispatcher = new ProxyAgent(proxyUrl({ country: "de" }));
await fetch(url, { dispatcher });

Garder proxyUrl exporté séparément est ce qui permet au chemin fetch de partager la configuration avec les deux autres sans dupliquer la construction de chaîne.

Réutilisez les agents, et décidez des sessions à l’avance

Un agent contient un pool de connexions. En construire un par requête jette ce pool à la poubelle à chaque fois, ce qui se manifeste par une latence que vous diagnostiquerez à tort comme un problème réseau.

Construisez les agents une fois par configuration utilisée et mettez-les en cache. Si vous faites une rotation sur cinq pays, cela représente cinq agents conservés pendant toute la durée de vie du processus, pas un par requête.

Les sessions sont la décision connexe. Sans identifiant de session, la passerelle effectue une rotation, ce qui est ce que vous voulez pour des requêtes indépendantes. Avec sid, vous obtenez une IP persistante, conservée pendant le ttl que vous spécifiez, ce qui est ce que vous voulez pour tout ce qui nécessite une continuité : un ensemble de résultats paginés, un flux à plusieurs étapes, tout ce où la deuxième requête doit provenir du même endroit que la première. La durée de persistance par défaut est de 120 secondes si vous n’en définissez pas une.

Choisir cela au moment de la mise en place plutôt qu’à chaque point d’appel fait la différence entre une politique de rotation cohérente et une base de code où la moitié des requêtes se trouvent par hasard être persistantes. Les compromis sont exposés dans proxies résidentiels persistants vs rotatifs.

Vérifiez avant de construire dessus

Écrivez le script de vérification avant le scraper. Cela prend cinq minutes et cela transforme toute une catégorie de confusion future en une réponse immédiate.

import { agentFor } from "./proxy.js";
import axios from "axios";
const agent = agentFor({ country: "de" });
const { data } = await axios.get("https://api.ipify.org?format=json", {
httpsAgent: agent,
proxy: false,
});
console.log(data);

Si cela affiche votre propre adresse, c’est que l’agent n’est pas attaché et que chaque requête du projet part en direct. C’est un état dans lequel il est vraiment courant de rester pendant des jours, car rien n’échoue : le code fonctionne, il n’utilise simplement pas le proxy. Vérifier que le pays correspond bien à ce que vous avez demandé est la seconde moitié de la vérification, et la méthode pour le faire correctement se trouve dans tester la vitesse, le taux de succès et la précision de localisation d’un proxy.

Faites-en un script dans package.json pour que quiconque puisse l’exécuter quand quelque chose semble anormal.

Cartographiez les erreurs une bonne fois pour toutes

Les erreurs de proxy sont suffisamment spécifiques pour être diagnostiquées automatiquement, et le faire à un seul endroit vaut mieux que de les interpréter à répétition à trois heures du matin :

  • 407 signifie que les identifiants sont incorrects ou qu’un indicateur de ciblage est mal formé. Un indicateur mal orthographié atterrit ici, c’est pourquoi il vaut la peine de vérifier les noms de vos indicateurs avant votre mot de passe.
  • 502 signifie qu’aucune sortie ne correspond à votre filtre. Le filtre est trop restrictif plutôt que le réseau étant en panne.
  • 509 signifie que le quota de bande passante est épuisé.
  • Connexion refusée signifie généralement un hôte ou un port hérité d’une ancienne configuration.

Seuls les échecs transitoires méritent une nouvelle tentative. Réessayer un 407 en boucle épuise votre limite de débit contre un problème qui ne se résoudra jamais de lui-même, et réessayer un 509 ne sert absolument à rien. Enveloppez les tentatives dans un vrai backoff plutôt qu’un délai fixe, comme expliqué dans limitation de débit et régulation des requêtes.

Limitez la concurrence de manière délibérée

Node démarrera volontiers dix mille requêtes, et aucun des trois clients ne vous en empêchera. Sous un proxy, c’est pire que d’habitude, car chacune de ces requêtes est un tunnel qui doit être établi.

Utilisez un limiteur de concurrence dès le départ plutôt que d’en ajouter un après le premier incident. Une limite modeste avec un débit constant surpasse une rafale non bornée qui déclenche des défenses puis passe son temps à réessayer.

Développement, CI et production diffèrent

Trois remarques pratiques qui reviennent dans chaque projet Node une fois que les proxies y sont intégrés.

Le trafic résidentiel est facturé à la bande passante, donc une suite de tests qui frappe de vraies cibles à travers le proxy est une facture récurrente sans aucun bénéfice. Simulez la couche HTTP dans les tests unitaires et conservez un petit nombre de requêtes réelles dans une vérification séparée, déclenchée manuellement.

Le développement local devrait utiliser le même module et les mêmes variables d’environnement que la production, avec des valeurs différentes. Une configuration qui n’existe qu’en production est une configuration que personne n’a testée.

Et les images de conteneurs ne devraient pas intégrer d’identifiants en dur. Passez-les au moment de l’exécution, comme n’importe quel autre secret.

FAQ

Ai-je besoin de https-proxy-agent si je n’utilise que fetch ?

Non. Le ProxyAgent d’undici couvre ce chemin. Vous avez besoin du package d’agent séparé pour Axios et Got.

Pourquoi Axios a-t-il besoin de proxy: false alors que je lui ai déjà donné un agent ?

Parce qu’Axios essaierait sinon d’appliquer sa propre gestion de proxy par-dessus l’agent, et les deux ne se combinent pas. Le mettre à false confie entièrement le travail à l’agent.

Puis-je définir le ciblage par requête plutôt que par agent ?

Vous le pouvez, mais chaque configuration distincte est un agent distinct, donc en construire un par requête vous coûte le pool de connexions. Mettez-les en cache par clé de configuration.

Le pays devrait-il être une valeur de configuration ou un argument par appel ?

Les deux, en pratique. Une valeur par défaut dans la configuration, modifiable par appel pour les tâches qui nécessitent une région spécifique. Ce qu’il faut éviter, c’est que le pays apparaisse comme une valeur littérale à l’intérieur des scrapers individuels.

En résumé

Le câblage de proxy en Node est petit et bien compris. Ce qui détermine si un projet reste maintenable, c’est l’organisation autour de lui : un module unique qui construit les agents à partir de la configuration, des identifiants qui vivent dans l’environnement, des agents réutilisés plutôt que reconstruits, une politique de session choisie délibérément, un script de vérification qui existe avant le scraper, et une gestion des erreurs qui sait faire la différence entre un filtre trop restrictif et un mot de passe erroné.

Mettez cela en place une fois, et ajouter une bibliothèque cliente ou une nouvelle région devient un changement de configuration. Faites l’impasse dessus, et chaque nouvelle exigence devient une recherche dans la base de code pour trouver des chaînes codées en dur. Les détails de la passerelle se trouvent sur la page des proxies résidentiels, avec les tarifs de bande passante sur la page de tarification.

Prêt à commencer ?

Essayez les proxies résidentiels de Shifter, 205M+ IPs, 195+ pays, à partir de 0,75 $/GB.

Commencer