Wissen

Residential Proxies in Node.js mit Axios und Got verwenden

Proxies in Node.js: warum Axios https-proxy-agent und proxy:false braucht, Gots agent-Option, undicis ProxyAgent für fetch, und Geo-Rotation pro Anfrage.

Chris Collins

Chris Collins

29. Juli 2026 · 8 Min. Lesezeit

Node.js ist die Standard-Runtime für eine riesige Menge an Scraping- und Automatisierungsarbeit: ein Event Loop, der Tausende gleichzeitige Anfragen mit einem Achselzucken abtut, ein gewaltiges Paket-Ökosystem und dieselbe Sprache von vorne bis hinten. Einen Residential Proxy einzubinden sind ein paar Zeilen, aber die Details lassen Leute auf eine Node-spezifische Art stolpern, denn der beliebteste HTTP-Client, Axios, hat eine Proxy-Option, die über HTTPS nicht das tut, was du erwartest. Bring den Agent richtig hin, und der Rest ist einfach.

Das ist der Node.js-Beitrag derselben Serie wie Residential Proxies mit Python, mit Playwright und mit Go: der Code, der für Axios, Got und das native fetch funktioniert, plus die Fallen, die dem Node-Ökosystem eigen sind.

Alles unten nutzt Shifters Residential Gateway: ein Endpunkt, p.shifter.io:443, mit dem gesamten Targeting im Benutzernamen kodiert. Tausche Host und Zugangsdaten für einen anderen Anbieter aus; die Form bleibt gleich.

Das Gateway-Modell in einem Absatz

Der Proxy-Benutzername trägt deine Authentifizierung und dein Targeting. Du wechselst nicht den Endpunkt, um Land oder Session zu ändern, du änderst die Benutzernamen-Zeichenkette:

customer-USERNAME-country-us-sid-abc123-ttl-600

country-us zielt auf die USA, sid fixiert eine Sticky Session, ttl hält diese IP für N Sekunden. Lässt du sid/ttl weg, rotiert jede neue Verbindung. Das Passwort bleibt konstant. In Node geht diese ganze Zeichenkette in die Proxy-URL, die du einem Proxy-Agent übergibst.

Axios: nutze einen Agent, nicht die eingebaute proxy-Option

Hier ist das Wichtigste in diesem Beitrag. Axios hat eine proxy-Option, und für HTTPS-Ziele mit Authentifizierung ist sie unzuverlässig, sie öffnet keinen ordentlichen CONNECT-Tunnel und schlägt still fehl oder leakt deine echte IP. Die Lösung, auf die sich das Ökosystem geeinigt hat, ist, Axios einen httpsAgent zu übergeben, gebaut mit https-proxy-agent, und proxy: false zu setzen, damit Axios nicht versucht, den Proxy selbst zu behandeln.

import axios from 'axios';
import { HttpsProxyAgent } from 'https-proxy-agent';
const user = `${process.env.SHIFTER_USER}-country-us`;
const pass = process.env.SHIFTER_PASS;
const proxyUrl = `http://${user}:${pass}@p.shifter.io:443`;
const agent = new HttpsProxyAgent(proxyUrl);
const client = axios.create({
httpsAgent: agent,
proxy: false, // kritisch: lass den Agent es behandeln, nicht Axios
timeout: 30000,
});
const res = await client.get('https://api.ipify.org');
console.log(res.data); // eine US-Residential-IP

Zwei Dinge zum Verinnerlichen. Die user-Zeichenkette enthält die Targeting-Flags (-country-us), weil die Geo dort lebt. Und proxy: false ist nicht optional, ohne es kollidiert Axios’ eigene Proxy-Logik mit dem Agent und du bekommst genau das kaputte Verhalten, das du vermeiden wolltest. Diese eine Zeile ist der häufigste Node-Proxy-Bug.

Got: der Agent kommt in den agent.https-Slot

Got nimmt den Proxy-Agent über seine agent-Option, nach Protokoll indiziert. Derselbe https-proxy-agent darunter, ohne den proxy: false-Tanz, weil Got keine eingebaute Proxy-Behandlung hat, mit der man kämpfen müsste.

import got from 'got';
import { HttpsProxyAgent } from 'https-proxy-agent';
const proxyUrl = `http://${user}:${pass}@p.shifter.io:443`;
const res = await got('https://api.ipify.org', {
agent: { https: new HttpsProxyAgent(proxyUrl) },
timeout: { request: 30000 },
});
console.log(res.body); // eine US-Residential-IP

Eine Packaging-Anmerkung: Got ist seit v12 reines ESM, also braucht import got from 'got' ein ESM-Projekt ("type": "module" in package.json) oder ein dynamisches import(). Steckst du auf CommonJS fest, bleib entweder auf Got v11 oder wechsle zu Axios/undici. Diese ESM-vs-CommonJS-Trennung ist ein Node-spezifischer Stolperstein, kein Proxy-Problem, aber sie beißt Leute, die das zum ersten Mal aufsetzen.

Natives fetch: undicis ProxyAgent als Dispatcher

Node 18+ liefert ein globales fetch, das von undici gestützt wird, und undici hat eigene Proxy-Unterstützung, die https-proxy-agent gar nicht nutzt. Du übergibst einen ProxyAgent als den dispatcher der Anfrage:

import { ProxyAgent } from 'undici';
const dispatcher = new ProxyAgent(`http://${user}:${pass}@p.shifter.io:443`);
const res = await fetch('https://api.ipify.org', { dispatcher });
console.log(await res.text()); // eine US-Residential-IP

Um jedes fetch im Prozess durch den Proxy zu leiten, setze ihn stattdessen global:

import { setGlobalDispatcher, ProxyAgent } from 'undici';
setGlobalDispatcher(new ProxyAgent(proxyUrl));

Bist du auf modernem Node und willst null HTTP-Client-Abhängigkeiten, ist das der sauberste Weg.

Falle 1: verwende den Agent wieder, baue nicht einen pro Anfrage

Welchen Client du auch wählst, der Proxy-Agent besitzt den Verbindungspool. Für jede Anfrage einen frischen HttpsProxyAgent oder ProxyAgent zu konstruieren, wirft Keep-Alive weg und zahlt jedes Mal einen vollständigen TCP- + TLS-Handshake durch den Proxy, den Overhead, den der Latenz-Leitfaden beseitigen soll. Baue den Agent einmal für eine gegebene Identität und verwende ihn über Anfragen hinweg wieder. Erzeuge den Axios/Got-Client (oder den undici-Dispatcher) beim Start und halte ihn.

Falle 2: begrenze deine Nebenläufigkeit, der Event Loop tut es nicht für dich

Nodes Event Loop macht es trivial, tausend Anfragen auf einmal abzufeuern, und nichts hält dich auf. await Promise.all(urls.map(fetchOne)) über ein großes Array öffnet jede Verbindung gleichzeitig, was auf deiner Seite Sockets erschöpft und für das Ziel wie ein Angriff aussieht. Begrenze Anfragen in Flug mit einem kleinen Nebenläufigkeits-Limiter (p-limit ist die übliche Wahl) oder einer einfachen Warteschlange:

import pLimit from 'p-limit';
const limit = pLimit(8); // höchstens 8 Anfragen in Flug
const results = await Promise.all(
urls.map(url => limit(() => client.get(url)))
);

Begrenze die Nebenläufigkeit pro Ziel-Host, nicht nur global, damit eine fragile Seite nicht malträtiert wird, während eine großzügige verhungert. Mehr Parallelität jenseits der Toleranz eines Ziels kauft Blockaden, keinen Durchsatz (wie man Blockaden vermeidet). Passe das Limit an das an, was jeder Host toleriert.

Falle 3: async-Fehler brauchen explizite Behandlung

Ein Proxy- oder Verbindungsfehler taucht als abgelehntes Promise auf, und eine unbehandelte Ablehnung kann den Prozess crashen oder, schlimmer, still eine Aufgabe in einem Batch fallenlassen. Umschließe jede Anfrage, damit ein Transportfehler mit einer frischen Identität erneut versucht, statt den Lauf umzuwerfen:

async function fetchWithRetry(client, url, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await client.get(url);
} catch (err) {
if (i === attempts - 1) throw err;
// transient (ECONNRESET, Timeout, Proxy 5xx): zurückfahren und erneut versuchen
await new Promise(r => setTimeout(r, 500 * 2 ** i));
}
}
}

Unterscheide eine kaputte Verbindung, die einen Retry wert ist, von einer bewussten Verlangsamung; ein Timeout ist ein kaputter Versuch, ein 429 ist der Server, der um Raum bittet, und sollte zurückfahren, nicht hämmern.

Geo und Sessions rotieren

Da das Targeting im Benutzernamen lebt, ist eine andere Identität eine andere Proxy-URL, was einen anderen Agent bedeutet. Das effiziente Muster ist, einen Agent pro Identität zu cachen, damit du den Verbindungspool pro Session behältst, statt ihn neu zu bauen:

const agents = new Map();
function agentFor(country, sid) {
const key = `${country}:${sid ?? 'rotate'}`;
if (!agents.has(key)) {
const u = `${process.env.SHIFTER_USER}-country-${country}` +
(sid ? `-sid-${sid}-ttl-600` : '');
const url = `http://${u}:${process.env.SHIFTER_PASS}@p.shifter.io:443`;
agents.set(key, new HttpsProxyAgent(url));
}
return agents.get(key);
}
// pro Anfrage:
await axios.get(targetUrl, { httpsAgent: agentFor('de', 'job-42'), proxy: false });

Gib jeder logischen Arbeitseinheit ihre eigene sid und rotiere zwischen Einheiten, nicht mitten im Fluss (Sticky vs. rotierend behandelt die Unterscheidung), und ordne Arbeit Identitäten so zu, wie es der Beitrag zum Lastausgleich beschreibt.

Prüfe, dass du wirklich über den Proxy läufst

Bevor du irgendetwas anderes benchmarkst oder debuggst, bestätige die Exit-IP:

const res = await client.get('http://ip-api.com/json');
console.log(res.data); // erwarte eine Residential-IP im Zielland

Deine eigene IP bedeutet, dass der Agent nicht angewandt wird (bei Axios fast immer ein fehlendes proxy: false). Ein Hänger bedeutet, dass der lokale Ausgang blockiert ist. Beides wird im Leitfaden zur Timeout-Diagnose behandelt.

FAQ

Warum funktioniert Axios’ proxy-Option nicht mit meinem HTTPS-Proxy? Axios’ eingebaute proxy-Option tunnelt HTTPS mit Authentifizierung nicht zuverlässig. Nutze einen httpsAgent, gebaut mit https-proxy-agent, und setze proxy: false, damit Axios aufhört, es zu behandeln. Diese Kombination ist der zuverlässige Weg und behebt das Symptom “es gibt meine echte IP zurück”.

Brauche ich https-proxy-agent, wenn ich natives fetch nutze? Nein. Node 18+ fetch wird von undici gestützt, das einen eigenen ProxyAgent hat, den du als dispatcher übergibst (oder global mit setGlobalDispatcher setzt). https-proxy-agent ist für Axios, Got und die eingebauten http/https-Module.

Warum wirft import got from 'got' in meinem Projekt? Got ist seit v12 reines ESM, also braucht es ein ESM-Projekt ("type": "module") oder ein dynamisches import(). Auf CommonJS bleib auf Got v11 oder nutze Axios/undici. Das ist eine Frage des Modulsystems, keine Proxy-Frage.

Wie rotiere ich IPs pro Anfrage in Node.js? Variiere den Proxy-Benutzernamen, was eine andere Proxy-URL und einen anderen Agent bedeutet. Cache einen Agent pro Identität in einer Map, damit jede Session ihren eigenen Verbindungspool behält, und wähle den Agent pro Anfrage. Lass die sid im Benutzernamen weg, um bei jeder neuen Verbindung zu rotieren.

Axios, Got oder fetch zum Scrapen? Alle drei funktionieren. Natives fetch + undici hat auf modernem Node null Extra-Abhängigkeiten; Got hat ergonomische Retries und Streams; Axios ist allgegenwärtig und vertraut, braucht aber die proxy: false-Korrektur. Wähle nach Ergonomie und bestehenden Abhängigkeiten, die Proxy-Konfiguration und die Fallen oben gelten für alle drei.

Das Fazit

Node.js plus Residential Proxies ist schnell aufgesetzt, sobald du die eine nicht offensichtliche Regel kennst: bei Axios nutze einen https-proxy-agent und setze proxy: false, nie die eingebaute proxy-Option; bei Got kommt der Agent in agent.https; bei nativem fetch übergib einen undici-ProxyAgent als Dispatcher. Dann verwende den Agent wieder, damit Verbindungen warm bleiben, begrenze deine Nebenläufigkeit, weil der Event Loop es nicht tut, behandle async-Fehler, damit eine schlechte Anfrage erneut versucht statt zu crashen, und variiere den Proxy-Benutzernamen, um Geo oder Session zu wechseln.

Mach das richtig, und Node bewältigt nebenläufige Sammlung so gut wie irgendetwas. Richte es auf das Residential Gateway, und denk daran, dass die Pool-Qualität entscheidet, wie oft du überhaupt erneut versuchst (IP-Reputation). Die Preisseite hat die Pro-GB-Tarife, um es gegen deine eigenen Ziele zu testen.

Bereit, loszulegen?

Testen Sie Shifters Residential-Proxys, 205M+ IPs, 195+ Länder, ab $0.75/GB.

Jetzt starten