Python'da proxy tanımlamak çoğu kütüphanede tek bir proxies parametresidir. Node.js'te ise durum biraz daha dağınıktır: yerleşik fetch, Axios ve node-fetch proxy'yi üç farklı mekanizmayla alır, SOCKS5 için ayrı bir paket gerekir ve bir kütüphaneye yanlış seçeneği verdiğinizde çoğu zaman hata bile almazsınız; istek sessizce proxy'siz gider. Hangi kütüphanenin hangi seçeneği okuduğunu bilmek bu yüzden önemlidir.
Bu yazıda Node.js'te proxy ayarlamanın üç temel yolunu (ortam değişkeni, agent ve dispatcher), yerleşik fetch, Axios ve node-fetch ile kimlik doğrulamalı proxy kullanımını, SOCKS5 proxy'yi ve IP rotasyonu ile yeniden denemeyi çalışan kodlarla anlatıyoruz. Örnekleri Node.js 24 üzerinde, kullanıcı adı ve şifre isteyen yerel bir test proxy'si üzerinden çalıştırdık; karşılaştığımız sürüm uyumsuzluğunu ve kimlik doğrulama hatalarının kütüphaneden kütüphaneye nasıl farklı göründüğünü de not ettik.
Node.js'te proxy ayarlamanın yolları
Node.js'te bir HTTP isteğini proxy'den geçirmenin üç mekanizması vardır. Hangi kütüphaneyi kullandığınız, hangi mekanizmanın çalışacağını belirler.
- Ortam değişkeni.
HTTP_PROXY,HTTPS_PROXYveNO_PROXYdeğişkenleri. Kod değiştirmeden bütün betiği proxy'den geçirir; ancak her kütüphane bu değişkenleri okumaz. - Agent. Node.js'in klasik
httpvehttpsmodülleri bağlantıyı birAgentnesnesi üzerinden kurar. Axios ve node-fetch bu modülleri kullandığı için proxy'ye bağlanan bir ajan (örneğinHttpsProxyAgent) verildiğinde istekler proxy'den geçer. - Dispatcher. Node.js'in yerleşik
fetchfonksiyonu klasikhttpmodülünü değil, undici adlı istemciyi kullanır. undici'de bağlantıyı yöneten nesnenin adıdispatcher'dır ve proxy içinProxyAgentverilir.
Bu ayrım yazının en önemli noktasıdır: yerleşik fetch agent seçeneğini tanımaz. Axios alışkanlığıyla fetch(url, { agent }) yazarsanız hata almazsınız, istek proxy'siz gider.
Proxy'nin genel çalışma mantığını ve HTTPS isteklerinde kurulan CONNECT tünelini Proxy Sunucu Nedir ve Nasıl Çalışır? yazımızda anlattık. cURL komutlarını fetch ve Axios'a çevirmek (başlık, gövde, form verisi) ise JavaScript'te cURL yazımızın konusu; bu yazı yalnızca proxy tarafına odaklanır.
Yerleşik fetch ile proxy nasıl kullanılır?
undici ProxyAgent
undici paketini kurun:
npm install undiciArdından fetch ve ProxyAgent'ı aynı paketten alın:
import { fetch, ProxyAgent } from "undici";
const dispatcher = new ProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
const res = await fetch("https://httpbin.org/ip", {
dispatcher,
signal: AbortSignal.timeout(20_000),
});
console.log(res.status, await res.json());Proxy adresi http:// ile başlasa da hedef HTTPS sitelere güvenle gidebilirsiniz: ProxyAgent proxy ile bir CONNECT tüneli kurar ve TLS bağlantısı bu tünelin içinde hedefle yapılır.
Sürüm uyumsuzluğu tuzağı. Node.js kendi içinde bir undici sürümü taşır; npm'den kurduğunuz undici bundan daha yeni olabilir. npm'den gelen ProxyAgent'ı Node.js'in yerleşik fetch fonksiyonuna verdiğimizde (import etmeden global fetch ile) Node.js 24.11 ve undici 8.10 ikilisinde istek fetch failed hatasıyla düştü; hatanın nedeni invalid onRequestStart method idi. Aynı ajanı undici'nin kendi fetch'iyle kullandığımızda sorun olmadı. Kural basit: ProxyAgent'ı hangi paketten aldıysanız fetch'i de oradan alın.
Uygulamadaki bütün undici fetch çağrılarının aynı proxy'yi kullanması için genel bir dispatcher tanımlanabilir:
import { fetch, ProxyAgent, setGlobalDispatcher } from "undici";
setGlobalDispatcher(new ProxyAgent("http://kullanici:parola@pr.proxynet.io:8000"));
const res = await fetch("https://httpbin.org/ip"); // dispatcher yazmaya gerek yokNODE_USE_ENV_PROXY ile ortam değişkeni
Güncel Node.js sürümlerinde yerleşik fetch, NODE_USE_ENV_PROXY etkinleştirildiğinde standart proxy ortam değişkenlerini okur. Node.js'in ağ yapılandırma rehberine göre özellik 22.21.0 ve 24.5.0 sürümlerinden itibaren kullanılabilir; aynı davranış --use-env-proxy komut satırı seçeneğiyle de açılır.
Linux ve macOS'ta:
NODE_USE_ENV_PROXY=1 HTTPS_PROXY="http://kullanici:parola@pr.proxynet.io:8000" node uygulama.mjsWindows PowerShell'de:
$env:NODE_USE_ENV_PROXY = "1"
$env:HTTPS_PROXY = "http://kullanici:parola@pr.proxynet.io:8000"
node uygulama.mjsBu yöntemde kod tarafında hiçbir değişiklik gerekmez; fetch("https://httpbin.org/ip") doğrudan proxy'den geçer. Testimizde aynı komut NODE_USE_ENV_PROXY olmadan çalıştırıldığında HTTPS_PROXY tanımlı olmasına rağmen istek proxy'ye hiç uğramadı. İç ağ adreslerini NO_PROXY değişkeniyle proxy dışında tutabilirsiniz.
Ortam değişkenlerini kod içinden okuyan bir dispatcher isterseniz undici'nin EnvHttpProxyAgent sınıfı da aynı işi yapar:
import { fetch, EnvHttpProxyAgent } from "undici";
const res = await fetch("https://httpbin.org/ip", { dispatcher: new EnvHttpProxyAgent() });Axios ile proxy nasıl kullanılır?
Axios, Node.js'te klasik http ve https modüllerini kullanır ve proxy için iki yol sunar.
Yerleşik proxy seçeneği
Axios'un istek yapılandırmasındaki proxy seçeneği, şifresiz http:// adresler için çalışır:
import axios from "axios";
const { data } = await axios.get("http://httpbin.org/ip", {
proxy: {
protocol: "http",
host: "pr.proxynet.io",
port: 8000,
auth: { username: "kullanici", password: "parola" },
},
timeout: 20_000,
});
console.log(data);Burada auth alanına yazılan şifre kodlanmaz; özel karakterleri olduğu gibi yazabilirsiniz.
HTTPS adresler için https-proxy-agent
Hedef adres HTTPS olduğunda tünelin ajan tarafından kurulması daha güvenilir sonuç verir:
npm install axios https-proxy-agentimport axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const httpsAgent = new HttpsProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
const client = axios.create({
httpsAgent,
proxy: false, // Axios'un kendi proxy mantığını kapatır, tüneli ajana bırakır
timeout: 20_000,
});
const { status, data } = await client.get("https://httpbin.org/ip");
console.log(status, data);proxy: false satırını atlamayın. Axios, proxy seçeneği verilmediğinde ortam değişkenlerindeki proxy'yi kendi mantığıyla uygulamaya çalışabilir; bu, ajanla çakışan iki farklı proxy davranışı demektir. Ajanı axios.create ile bir kez bağlamak, her çağrıda tekrar yazmanızı önler.
node-fetch ile proxy nasıl kullanılır?
node-fetch, yerleşik fetch gelmeden önce Node.js'te en yaygın fetch uygulamasıydı ve eski projelerde hâlâ sık görülür. Yerleşik fetch'in aksine klasik http modülünü kullandığı için proxy agent seçeneğiyle verilir:
npm install node-fetch https-proxy-agentimport fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://kullanici:parola@pr.proxynet.io:8000");
const res = await fetch("https://httpbin.org/ip", { agent });
console.log(res.status, await res.json());node-fetch'in 3. sürümü yalnızca ES modülü olarak yayınlanır; require kullanan bir CommonJS projesinde import ile yükleyemiyorsanız yerleşik fetch'e geçmek genellikle daha az zahmetlidir. Yeni bir projede node-fetch eklemek için bir neden yoktur.
SOCKS5 proxy nasıl kullanılır?
undici'nin ProxyAgent'ı HTTP proxy içindir; yerleşik fetch'in SOCKS5 desteği yoktur. SOCKS5 proxy ile çalışmak için socks-proxy-agent paketi Axios ve node-fetch ile birlikte kullanılır:
npm install socks-proxy-agentimport axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";
// socks5h: alan adı proxy tarafında çözülür, DNS sorgusu sizin ağınızdan çıkmaz
const agent = new SocksProxyAgent("socks5h://kullanici:parola@pr.proxynet.io:1080");
const { data } = await axios.get("https://httpbin.org/ip", {
httpAgent: agent,
httpsAgent: agent,
proxy: false,
});
console.log(data);Aynı ajan node-fetch'te fetch(url, { agent }) biçiminde verilir. Test proxy'mizin kayıtlarında socks5h:// şemasıyla gönderilen isteklerin proxy'ye IP adresi değil alan adı olarak ulaştığını gördük. socks5:// şeması ise alan adını sizin bilgisayarınızda çözer; bunun hangi sorunlara yol açtığını WebRTC ve DNS Sızıntısı yazımızda anlattık. SOCKS5 ile HTTP proxy arasında seçim yapmadan önce SOCKS ve HTTP Proxy Farkı yazımıza bakabilirsiniz.
Kütüphaneler proxy'yi nasıl alır?
| İstemci | Proxy nasıl verilir? | Ortam değişkeni | SOCKS5 | Kimlik doğrulama hatası |
|---|---|---|---|---|
| Yerleşik fetch | NODE_USE_ENV_PROXY veya --use-env-proxy | Yalnızca bayrakla | Yok | fetch failed |
undici fetch | dispatcher: new ProxyAgent(...) | EnvHttpProxyAgent ile | Yok | fetch failed, neden: istek iptal edildi |
| Axios | proxy seçeneği veya httpsAgent + proxy: false | Seçenek verilmezse | socks-proxy-agent ile | Durum kodu 407 olan hata |
| node-fetch | agent | Yok | socks-proxy-agent ile | Kullanılan ajana bağlı |
http.request | agent | Yok | socks-proxy-agent ile | Kullanılan ajana bağlı |
Tablonun son sütunu hata ayıklarken önemlidir. Yanlış şifreyle yaptığımız denemede Axios, Request failed with status code 407 mesajı ve error.response.status === 407 değeriyle nedeni açıkça gösterdi. undici'nin fetch'i ise yalnızca fetch failed hatası verdi ve nedeni "Request was cancelled" olarak bildirdi; mesajın kendisi kimlik doğrulamadan söz etmiyor. undici ile fetch failed görüyorsanız ilk kontrol edilecek şey proxy kullanıcı adı ve şifresidir. 407'nin tüm nedenlerini Proxy Kimlik Doğrulama: User:Pass ve IP Whitelist yazımızda topladık.
Kimlik bilgileri ve özel karakterler
Proxy adresini URL olarak veren bütün yöntemlerde (undici ProxyAgent, https-proxy-agent, socks-proxy-agent, ortam değişkenleri) şifredeki @, :, / ve # gibi karakterler kodlanmalıdır. Aksi hâlde adres yanlış ayrıştırılır.
const user = process.env.PROXY_USER;
const pass = encodeURIComponent(process.env.PROXY_PASS);
const proxyUrl = `http://${user}:${pass}@pr.proxynet.io:8000`;Bilgileri kodun içine yazmak yerine ortam değişkeninden okumak, kodun paylaşıldığı her yerde şifrenin görünmesini önler. Axios'un proxy.auth alanında ise şifre kodlanmadan yazılır.
IP rotasyonu ve yeniden deneme
Gerçek bir veri toplama işinde istekler zaman zaman başarısız olur: proxy'nin çıkış noktası hedefe ulaşamaz, hedef 429 veya 503 döner, bağlantı zaman aşımına uğrar. Aşağıdaki örnek birden fazla proxy arasından rastgele seçim yapar, başarısız isteği üstel beklemeyle yeniden dener ve aynı anda çalışan istek sayısını küçük gruplarla sınırlar:
import { fetch, ProxyAgent } from "undici";
const PROXIES = [
"http://kullanici:parola@pr.proxynet.io:8000",
"http://kullanici:parola@pr.proxynet.io:8001",
];
const agents = PROXIES.map((p) => new ProxyAgent(p));
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function getWithRetry(url, { attempts = 4, baseMs = 500 } = {}) {
let lastError;
for (let i = 0; i < attempts; i++) {
const dispatcher = agents[Math.floor(Math.random() * agents.length)];
try {
const res = await fetch(url, { dispatcher, signal: AbortSignal.timeout(20_000) });
if (res.status === 429 || res.status >= 500) {
await res.body?.cancel();
throw new Error(`HTTP ${res.status}`);
}
return await res.text();
} catch (err) {
lastError = err;
await sleep(baseMs * 2 ** i + Math.random() * 250);
}
}
throw lastError;
}
async function crawl(urls, concurrency = 5) {
const results = [];
for (let i = 0; i < urls.length; i += concurrency) {
const batch = urls.slice(i, i + concurrency);
results.push(...(await Promise.allSettled(batch.map((u) => getWithRetry(u)))));
}
return results;
}
const urls = ["https://httpbin.org/ip", "https://httpbin.org/status/503", "https://example.com/"];
const results = await crawl(urls, 2);
results.forEach((r, i) =>
console.log(urls[i], r.status, r.status === "fulfilled" ? `${r.value.length} bayt` : r.reason.message),
);Kodun üç ayrıntısı önemlidir:
Promise.allSettled, gruptaki bir isteğin başarısız olması diğerlerini durdurmaz.Promise.allkullansaydık tek bir503bütün grubun sonucunu kaybettirirdi. Örnekte/status/503adresi dört denemenin ardındanrejectedolarak işaretlendi, diğer adresler sonucunu döndürdü.res.body?.cancel(), yeniden deneyeceğimiz yanıtın gövdesini okumadan bağlantıyı serbest bırakır. Okunmayan gövdeler bağlantı havuzunu doldurabilir.- Rastgele bileşen (
Math.random() * 250), aynı anda başarısız olan isteklerin aynı anda yeniden denenip yeni bir yığılma oluşturmasını önler.
Proxy listesini kendiniz yönetmek yerine tek bir adres üzerinden her bağlantıda farklı çıkış IP'si veren Rotating Proxy kullanırsanız PROXIES dizisi tek elemana iner ve rotasyon sağlayıcı tarafında yapılır. Oturum boyunca aynı IP'nin korunması gereken işlerde (giriş yapılan sayfalar, çok adımlı akışlar) Sticky Proxy tercih edilir.
Bu örnek 429 yanıtında Retry-After başlığını okumaz. Başlığı dikkate alan ve hangi durum kodunda yeniden denenmemesi gerektiğini ayıran bir yaklaşımı Scraping'de HTTP Hata Kodları yazımızda anlattık. Eşzamanlılık değerinin hızı gerçekte nasıl etkilediğini ise Concurrency ve Parallelism yazımızda ele aldık.
Proxy'nin çalıştığı nasıl doğrulanır?
Her yeni kurulumda isteğin gerçekten proxy'den geçtiğini kontrol edin. En kolay yöntem, çıkış IP adresini döndüren bir adrese önce proxy'siz, sonra proxy ile istek atmaktır:
import { fetch, ProxyAgent } from "undici";
const ip = async (options = {}) => (await (await fetch("https://api.ipify.org?format=json", options)).json()).ip;
console.log("proxy'siz:", await ip());
console.log("proxy ile:", await ip({ dispatcher: new ProxyAgent(process.env.HTTPS_PROXY) }));İki satır aynı adresi gösteriyorsa istek proxy'den geçmiyordur. Bu durumda en sık neden, yerleşik fetch'e agent verilmesi ya da Axios'ta proxy: false yazılmadan ajan kullanılmasıdır.
Sık yapılan hatalar
- Yerleşik fetch'e
agentvermek. Seçenek sessizce yok sayılır. fetch için doğru anahtardispatcher'dır. - npm undici'nin
ProxyAgent'ını global fetch'e vermek. Sürümler uyuşmadığındafetch failedhatası alırsınız;fetch'i de undici'den import edin. HTTPS_PROXYtanımlayıp yerleşik fetch'in onu okuyacağını varsaymak.NODE_USE_ENV_PROXYveya--use-env-proxyolmadan okumaz.- Axios'ta ajanla birlikte
proxy: falseyazmamak. İki proxy mantığı çakışır. - Şifredeki özel karakterleri kodlamamak. Adres yanlış ayrıştırılır ve kimlik doğrulama başarısız olur.
socks5://ile DNS'i yerelde çözmek. Uzak çözümleme içinsocks5h://kullanın.- Zaman aşımı koymamak. Yanıt vermeyen bir proxy çıkışı, zaman aşımı olmayan bir isteği dakikalarca bekletir. undici'de
AbortSignal.timeout, Axios'tatimeoutkullanın. - Bütün isteği
Promise.allile tek seferde başlatmak. Hem kendi bağlantı havuzunuzu hem hedef sitenin hız sınırını zorlar.
Hangi yöntemi seçmeli?
| Durumunuz | Öneri |
|---|---|
| Yeni proje, bağımlılık az olsun | undici fetch + ProxyAgent |
| Kodu değiştirmeden mevcut betiği proxy'den geçirmek | NODE_USE_ENV_PROXY=1 + HTTPS_PROXY |
| Projede zaten Axios var | Axios + https-proxy-agent + proxy: false |
| Eski proje, node-fetch kullanıyor | node-fetch + agent |
| SOCKS5 proxy | Axios veya node-fetch + socks-proxy-agent (socks5h://) |
| Her istekte farklı IP | Rotating proxy, tek adres |
| Oturum boyunca aynı IP | Sticky proxy |
| Hata mesajlarının açık olması önemli | Axios (407'yi durum koduyla gösterir) |
Tarayıcıda çalışan JavaScript'te ise bunların hiçbiri geçerli değildir: tarayıcıdaki fetch proxy'yi koddan değiştiremez, proxy tarayıcının veya işletim sisteminin ayarında tanımlanır. Windows tarafındaki kurulum için Windows ve Chrome Proxy Ayarları yazımıza bakabilirsiniz.
Sık sorulan sorular
Node.js'in yerleşik fetch'i proxy destekliyor mu?
Node.js 22.21.0 ve 24.5.0'dan itibaren NODE_USE_ENV_PROXY=1 ortam değişkeni veya --use-env-proxy seçeneğiyle HTTP_PROXY ve HTTPS_PROXY değişkenlerini okur. Kod içinden istek bazında proxy vermek için ise undici paketinin fetch ve ProxyAgent'ı kullanılır.
Axios HTTPS_PROXY ortam değişkenini okur mu?
Node.js'te proxy seçeneği verilmediğinde Axios ortam değişkenlerindeki proxy'yi kullanmaya çalışır. Davranışın açık ve öngörülebilir olması için proxy'yi ajanla tanımlayıp proxy: false yazmanızı öneririz.
Her istekte farklı proxy kullanabilir miyim?
Evet. undici'de her fetch çağrısına farklı bir ProxyAgent, Axios'ta farklı bir httpsAgent verebilirsiniz. Ajanları her istekte yeniden oluşturmak yerine yukarıdaki örnekteki gibi bir kez oluşturup yeniden kullanın; her yeni ajan kendi bağlantı havuzunu açar.
Proxy kullanırken çerezler nasıl korunur?
Yerleşik fetch ve undici çerez saklamaz; Set-Cookie başlığını okuyup sonraki isteğe Cookie başlığı olarak eklemeniz gerekir. Axios'ta tough-cookie tabanlı bir çerez kavanozu kullanılabilir. Çerezlerle birlikte IP adresinin de oturum boyunca sabit kalması gerektiğini unutmayın.
Puppeteer veya Playwright'ta proxy nasıl verilir?
Tarayıcı otomasyon araçları proxy'yi Node.js kütüphaneleri gibi değil, tarayıcıyı başlatırken verilen seçenekle alır. Bu yazıdaki ajanlar tarayıcıyı etkilemez. Puppeteer tarafını Puppeteer ve CAPTCHA yazımızda gösterdik.
JavaScript mi Python mu tercih etmeliyim?
Proxy kullanımı iki dilde de mümkündür; Python'da kütüphanelerin çoğu tek bir parametreyle proxy alır, Node.js'te ise kütüphaneye göre mekanizma değişir. Seçimi genellikle ekibin dili ve hedef sayfaların yapısı belirler. Karşılaştırmayı Web Kazıma: JavaScript mi Python mu? yazımızda yaptık; Python kütüphaneleri için HTTPX, Requests ve AIOHTTP yazımıza bakabilirsiniz.
Özetle
Node.js'te proxy, kullandığınız istemciye göre üç farklı yoldan verilir: yerleşik fetch için undici dispatcher veya NODE_USE_ENV_PROXY, Axios ve node-fetch için agent. HTTPS hedeflerde Axios'u https-proxy-agent ve proxy: false ile, SOCKS5'i socks-proxy-agent ve socks5h:// şemasıyla kullanın. ProxyAgent ile fetch'i aynı paketten alın, şifreyi kodlayın, zaman aşımı koyun ve istekleri Promise.allSettled ile küçük gruplar halinde yeniden deneme mantığıyla çalıştırın. Veri toplama işleriniz için uygun paketleri veri kazıma çözümü sayfamızda bulabilirsiniz.




