Geliştirici Rehberleri
Yayın tarihi
Okuma süresi
3 dk okuma

Node.js ile Proxy Kullanımı: undici ve fetch

Node.js 20 ve 22'de fetch, undici ProxyAgent, https modülü ile CONNECT ve socks-proxy-agent kullanımı; kimlik doğrulama, zaman aşımı ve hata ayıklama örnekleriyle.

Node.js'te proxy kullanımı, hangi HTTP istemcisini seçtiğinize göre değişir. Yerleşik fetch proxy'yi kendiliğinden bilmez, https modülü ise yalnızca ayrı bir CONNECT isteğiyle çalışır. Bu rehber Node 20 ve 22 için üç yolu, çalışan örnekleriyle anlatır.

Örnekler ES modülü biçimindedir; dosyaları .mjs uzantısıyla kaydedin ya da package.json içine "type": "module" ekleyin. PROXY_HOST, PROXY_PORT, KULLANICI ve PAROLA yer tutucudur. Komutlar Windows ve Linux'ta aynıdır; fark yalnızca ortam değişkeni söz diziminde çıkar (aşağıda).

Hazırlık

Bash
node --version
npm init -y
npm i undici

Kimlik bilgisini kodun içine gömmeyin. Ortam değişkenlerinden okuyun:

Bash
# Linux ve macOS
export PROXY_HOST="PROXY_HOST" PROXY_PORT="PROXY_PORT"
export PROXY_USER="KULLANICI" PROXY_PASS="PAROLA"
PowerShell
# Windows PowerShell
$env:PROXY_HOST = "PROXY_HOST"; $env:PROXY_PORT = "PROXY_PORT"
$env:PROXY_USER = "KULLANICI"; $env:PROXY_PASS = "PAROLA"

1. undici ProxyAgent ile fetch

Node'un küresel fetch işlevi undici üzerine kuruludur. Proxy için ProxyAgent oluşturup dispatcher olarak verirsiniz. Kimlik doğrulamayı token seçeneğiyle, Basic başlığını kendiniz üreterek yapmak parola kodlama sorununu önler.

JavaScript
// proxy-fetch.mjs
import { fetch, ProxyAgent } from 'undici';

const { PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS } = process.env;

const dispatcher = new ProxyAgent({
  uri: `http://${PROXY_HOST}:${PROXY_PORT}`,
  token: 'Basic ' +
    Buffer.from(`${PROXY_USER}:${PROXY_PASS}`).toString('base64'),
});

const res = await fetch('https://api64.ipify.org', {
  dispatcher,
  signal: AbortSignal.timeout(15_000),
});
console.log(res.status, await res.text());

Çalıştırma: node proxy-fetch.mjs. Çıktıda proxy çıkış adresini görmelisiniz. api64.ipify.org hem IPv4 hem IPv6 ile erişilebilen bir adres yansıtma hizmetidir; sonuç IPv6 ise trafik IPv6'dan çıkıyordur.

Burada fetch işlevini doğrudan undici paketinden içe aktarmak bilinçli bir seçimdir. Node'un yerleşik fetch'i kendi içindeki undici sürümünü kullanır; npm'den kurduğunuz ProxyAgent başka bir sürümse, ikisini karıştırmak beklenmedik hatalara yol açabilir. Aynı paketten ikisini birlikte almak bu riski kaldırır.

Tüm istekler için küresel proxy

Her fetch çağrısına dispatcher yazmak istemiyorsanız küresel yönlendirici ayarlayın:

JavaScript
import { fetch, ProxyAgent, setGlobalDispatcher } from 'undici';

setGlobalDispatcher(new ProxyAgent(
  `http://${process.env.PROXY_HOST}:${process.env.PROXY_PORT}`
));

Küresel ayar bütün isteklerin proxy'den geçmesine yol açar; yerel servislere ya da başka API'lere giden istekleri de etkiler. Karışık kullanımda istek başına dispatcher vermek daha öngörülebilirdir.

Ortam değişkeninden okumak

Node çekirdeği HTTP_PROXY ve HTTPS_PROXY değişkenlerini varsayılan olarak okumaz; ayarlamanız yeterli olmaz. undici'nin yeni sürümleri bu iş için EnvHttpProxyAgent sunar:

JavaScript
import { fetch, EnvHttpProxyAgent } from 'undici';

const dispatcher = new EnvHttpProxyAgent(); // HTTP_PROXY, HTTPS_PROXY, NO_PROXY
const res = await fetch('https://example.com', { dispatcher });
console.log(res.status);

Yeni Node sürümlerinde ortam değişkenine yerleşik destek eklenmiş olabilir. Hangi sürümde nasıl çalıştığı için kullandığınız sürümün belgesine bakın; üretim kodunda davranışı sürüme bırakmayıp dispatcher ile açıkça belirtmeniz daha güvenlidir.

2. https modülü ile elle CONNECT

Bir HTTP proxy üzerinden HTTPS hedefe gitmek için önce proxy'ye CONNECT isteği gönderilir, tünel açıldıktan sonra TLS bu tünelin içinde kurulur (RFC 9110 §9.3.6 (yeni sekmede açılır)). CONNECT isteğinde hedef host:port biçimindedir ve port zorunludur. Aşağıdaki kod bunu kütüphanesiz yapar; proxy'nin ne yaptığını anlamak için iyi bir araçtır.

JavaScript
// connect.mjs
import http from 'node:http';
import https from 'node:https';

const { PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS } = process.env;
const hedef = 'api64.ipify.org';

const auth = Buffer.from(`${PROXY_USER}:${PROXY_PASS}`).toString('base64');

const req = http.request({
  host: PROXY_HOST,
  port: Number(PROXY_PORT),
  method: 'CONNECT',
  path: `${hedef}:443`,
  headers: { 'Proxy-Authorization': `Basic ${auth}`, Host: `${hedef}:443` },
  timeout: 10_000,
});

req.on('connect', (res, socket) => {
  if (res.statusCode !== 200) {
    console.error('CONNECT başarısız:', res.statusCode);
    socket.destroy();
    return;
  }
  https.get({ host: hedef, path: '/', socket, agent: false }, (r) => {
    let govde = '';
    r.on('data', (d) => (govde += d));
    r.on('end', () => console.log(r.statusCode, govde));
  }).on('error', (e) => console.error('TLS/İstek hatası:', e.message));
});

req.on('timeout', () => req.destroy(new Error('CONNECT zaman aşımı')));
req.on('error', (e) => console.error('Proxy hatası:', e.message));
req.end();

Proxy 407 dönerse kimlik bilgisi yanlıştır, 502 dönerse proxy hedefe ulaşamamıştır. Bu kodların cURL'deki karşılıkları ve ayırt etme yöntemi cURL ile proxy testi yazısında tablo halindedir. IPv6 proxy adresi kullanıyorsanız host alanına köşeli parantezsiz yazın (2001:db8::1); köşeli parantez yalnızca URL içinde gerekir.

3. SOCKS5 için socks-proxy-agent

undici ProxyAgent yalnızca HTTP/HTTPS proxy ile tünel açar. SOCKS5 için socks-proxy-agent paketini http ve https modülleriyle birlikte kullanabilirsiniz.

Bash
npm i socks-proxy-agent
JavaScript
// socks.mjs
import https from 'node:https';
import { SocksProxyAgent } from 'socks-proxy-agent';

const { PROXY_HOST, PROXY_PORT, PROXY_USER, PROXY_PASS } = process.env;
const user = encodeURIComponent(PROXY_USER);
const pass = encodeURIComponent(PROXY_PASS);

const agent = new SocksProxyAgent(
  `socks5h://${user}:${pass}@${PROXY_HOST}:${PROXY_PORT}`
);

https.get('https://api64.ipify.org', { agent, timeout: 15_000 }, (res) => {
  let govde = '';
  res.on('data', (d) => (govde += d));
  res.on('end', () => console.log(res.statusCode, govde));
}).on('error', (e) => console.error(e.message));

socks5h şemasıyla alan adı çözümü proxy'ye bırakılır. SOCKS5 protokolü RFC 1928 (yeni sekmede açılır) ve kullanıcı adı/parola doğrulaması RFC 1929 (yeni sekmede açılır) ile tanımlıdır; parola ağda düz metin taşınır.

Önemli

SOCKS5 kodu yazmadan önce ürünün bu protokolü sunduğundan emin olun. IPv6 Proxy paket özelliklerinde protokol HTTP(S) olarak geçer, SOCKS5 listelenmemiştir; gerekiyorsa siparişten önce destekten sorun. Bağlantının SOCKS5 konuşup konuşmadığını SOCKS5 kontrol aracıyla sınayabilirsiniz.

Hata ayıklama

fetch failed iletisi tek başına işe yaramaz. Asıl neden cause alanındadır.

JavaScript
try {
  const res = await fetch('https://example.com', {
    dispatcher,
    signal: AbortSignal.timeout(10_000),
  });
  console.log(res.status);
} catch (err) {
  console.error('İleti:', err.message);
  console.error('Neden:', err.cause?.code, err.cause?.message);
  if (err.name === 'TimeoutError') console.error('Zaman aşımı doldu');
}
BelirtiOlası neden
ECONNREFUSEDProxy adresi ya da port yanlış, servis kapalı
ETIMEDOUT, UND_ERR_CONNECT_TIMEOUTProxy'ye ağdan ulaşılamıyor, güvenlik duvarı
ENOTFOUNDProxy ya da hedef alan adı çözülemedi
İletide 407Kimlik bilgisi yanlış ya da eksik
İletide 502 veya tünel hatasıProxy hedefe ulaşamadı
TimeoutErrorAbortSignal.timeout süresi doldu

undici, tünel kurulamadığında proxy'nin döndüğü durum koduyla bir hata fırlatır (ileti, tünelin 200 yerine başka bir kod döndürdüğünü söyler). Hata ayıklamayı hızlandırmak için önce aynı bağlantıyı HTTP proxy kontrol aracıyla ya da cURL ile deneyin; sorun kodunuzda mı, proxy bilgilerinde mi olduğunu ayırt edersiniz.

Uyarı

Hedef yalnızca IPv4 yayın yapıyorsa fetch failed hatasının nedeni kodunuz değil adres ailesi olabilir: IPv6 çıkışlı bir proxy ona doğrudan bağlanamaz ve NAT64/DNS64 çevirisi gerekir. IPv6 Proxy sayfası böyle bir katmandan söz eder, ancak kapsamı doğrulanamamıştır; hedefinizi önceden deneyin.

Zaman aşımı ve eşzamanlılık

  • Her istekte AbortSignal.timeout(ms) kullanın; zaman aşımsız istek süreci sonsuza dek açık tutabilir.
  • Eşzamanlı istek sayısını sınırlayın. Aynı anda yüzlerce istek hem proxy'yi hem hedefi zorlar.
  • Hata alan isteği hemen tekrarlamayın; artan bekleme süresiyle (üstel geri çekilme) birkaç kez deneyin.
  • Kimlik bilgisini ortam değişkeninde ya da gizli bilgi yöneticisinde tutun, depoya göndermeyin.

Veri toplama gibi işlerde yasalara ve hedef sitenin kullanım koşullarına uyum sizin sorumluluğunuzdadır; yalnızca kamuya açık veriyle ve ölçülü hızla çalışın. Kullanım bağlamı için web scraping çözümü sayfasına, Python karşılığı için Python ile proxy kullanımı yazısına bakabilirsiniz.

Sık sorulan sorular

Node.js'in yerleşik fetch'i proxy kullanır mı?

Yerleşik fetch kendiliğinden proxy ayarı uygulamaz; proxy için undici'nin ProxyAgent nesnesini dispatcher olarak vermeniz gerekir. Yeni Node sürümlerinde ortam değişkeniyle yerleşik destek gelmiş olabilir, kullandığınız sürümün belgesine bakın.

Kimlik bilgisini proxy adresine mi yazmalıyım, token olarak mı vermeliyim?

İkisi de çalışır, ancak token seçeneğine Basic başlığını kendiniz üretmek özel karakterli parolalarda yüzde kodlaması derdini ortadan kaldırır. Parolayı kaynak koda değil ortam değişkenine koyun.

undici ile SOCKS5 proxy kullanabilir miyim?

undici ProxyAgent yalnızca HTTP/HTTPS proxy ile tünel açar. SOCKS5 için socks-proxy-agent paketini https modülüyle birlikte kullanabilirsiniz.

fetch failed hatasının nedeni nasıl bulunur?

İletinin kendisi bilgi vermez; asıl neden error.cause içindedir. cause.code değeri (ECONNREFUSED, ETIMEDOUT, UND_ERR_CONNECT_TIMEOUT gibi) sorunun adres, ağ ya da zaman aşımı olduğunu söyler.

/128Ürün

IPv6 Proxy ürününü inceleyin

Adet bazlı fiyatlanan IPv6 proxy paketleri. Satışı Sağlam Proxy (saglamproxy.com) üzerinden yapılır.