استخدام البروكسي في Deno و Bun: دليل المطور الشامل

دليل عملي بالأكواد لاستخدام البروكسي السكني في Deno و Bun — من إعداد Deno.createHttpClient و Bun fetch proxy إلى الجلسات اللاصقة والـ SOCKS5 والإنتاج بجودة عالية.

Using Proxies in Deno and Bun: A Code-First Guide for Modern JavaScript

إذا كنت تعمل بـ JavaScript أو TypeScript على أحدث بيئات التشغيل مثل Deno وBun، فمن المرجّح أنك استخدمت fetch() المدمجة لإرسال الطلبات. لكن عند محاولة تمرير الطلبات عبر بروكسي، ستكتشف سريعًا أن fetch() الأصلية تتجاهل إعدادات البروكسي افتراضيًا. في هذا الدليل نشرح استخدام البروكسي في Deno و Bun خطوة بخطوة مع أمثلة كود قابلة للتشغيل، ونغطي Deno.createHttpClient وخيار proxy في Bun fetch، وترميز الاستهداف الجغرافي والجلسات اللاصقة في اسم المستخدم، وبروتوكول SOCKS5 على المنفذ 1080، ونصائح الإنتاج مثل إعادة المحاولة مع التراجع وإعادة استخدام الاتصالات.

لماذا يتجاهل fetch() البروكسي افتراضيًا في Deno و Bun

تتبع كل من Deno و Bun معيار WHATWG Fetch الذي لا يحدد آلية بروكسي داخل المواصفة نفسها. بدلاً من ذلك، تُترك آلية البروكسي لبيئة التشغيل أو لطبقة الشبكة الأساسية. هذا يعني أن استدعاء fetch('https://example.com') لا يقرأ تلقائيًا متغيرات البيئة HTTP_PROXY أو HTTPS_PROXY في كل الحالات، ولا يوفّر خيارًا مباشرًا في الـ API القياسي لتمرير رابط البروكسي.

حلّت كل بيئة تشغيل هذه المشكلة بطريقتها الخاصة:

  • Deno يوفّر Deno.createHttpClient({ proxy: { url, basicAuth } }) الذي يُمرَّر كخيار { client } إلى fetch().
  • Bun يضيف خيار proxy مباشرةً في خيارات fetch() نفسها.

هذا الفرق في التصميم يعكس فلسفة كل بيئة: Deno يفضّل كائنات عميل قابلة لإعادة الاستخدام، بينما Bun يهدف إلى أبسط API ممكن.

إعداد بروكسي Deno باستخدام Deno.createHttpClient

في Deno، تنشئ كائن عميل HTTP مخصصًا عبر Deno.createHttpClient() وتمرّر إعدادات البروكسي داخله، ثم تمرّر هذا الكائن إلى fetch() عبر الخاصية client. هذا النهج يسمح بإعادة استخدام نفس العميل عبر طلبات متعددة، مما يحسّن الأداء من خلال إعادة استخدام الاتصالات (connection pooling).

إليك مثالًا أساسيًا باستخدام بروكسي ProxyHat عبر HTTP على المنفذ 8080:

// deno run --allow-net --unstable-net proxy_basic.ts

const client = Deno.createHttpClient({
  proxy: {
    url: "http://gate.proxyhat.com:8080",
    basicAuth: {
      username: "user-country-US",
      password: "pass",
    },
  },
});

try {
  const res = await fetch("https://httpbin.org/ip", { client });
  const body = await res.json();
  console.log("IP عبر البروكسي:", body);
} catch (err) {
  console.error("فشل الطلب:", err);
} finally {
  client.close();
}

لاحظ أن Deno.createHttpClient يتطلب علم --unstable-net في بعض إصدارات Deno. تحقق من وثائق Deno الرسمية لمعرفة حالة الاستقرار الحالية.

مصادقة البروكسي والاستهداف الجغرافي في Deno

يدعم ProxyHat ترميز الاستهداف الجغرافي والجلسات اللاصقة مباشرةً في اسم المستخدم. مثلاً، user-country-DE-city-berlin-session-abc123 يوجّه الطلب عبر IP سكني في برلين مع جلسة لاصقة تحافظ على نفس الـ IP طوال مدة الجلسة.

// جلسة لاصقة مع استهداف مدينة محددة
const stickyClient = Deno.createHttpClient({
  proxy: {
    url: "http://gate.proxyhat.com:8080",
    basicAuth: {
      username: "user-country-DE-city-berlin-session-abc123",
      password: "pass",
    },
  },
});

const res = await fetch("https://httpbin.org/headers", { client: stickyClient });
console.log(await res.text());
stickyClient.close();

استخدام Bun fetch proxy في سطر واحد

يوفّر Bun تجربة أبسط بكثير: مرّر رابط البروكسي مباشرةً في خيارات fetch(). لا حاجة لإنشاء كائن عميل منفصل. هذا مناسب للمهام السريعة والسكربتات البسيطة.

// bun run proxy_bun.ts

const res = await fetch("https://httpbin.org/ip", {
  proxy: "http://user-country-US:pass@gate.proxyhat.com:8080",
});

console.log(await res.json());

كما يدعم Bun ترميز اسم المستخدم بالكامل بما في ذلك الاستهداف الجغرافي والجلسات:

// استهداف مدينة مع جلسة لاصقة
const res2 = await fetch("https://httpbin.org/ip", {
  proxy: "http://user-country-GB-city-london-session-sess42:pass@gate.proxyhat.com:8080",
});
console.log(await res2.json());

مقارنة سريعة: Deno مقابل Bun للبروكسي

المعيارDenoBun
طريقة تمرير البروكسيDeno.createHttpClient + { client }{ proxy: '...' } مباشرةً
إعادة استخدام الاتصالنعم، عبر كائن العميلتُدار داخليًا
دعم SOCKS5عبر url: 'socks5://...'عبر proxy: 'socks5://...'
شهادات CA مخصصةنعم، عبر caCertsعبر متغيرات البيئة
الاستقرارقد يتطلب --unstable-netمستقر

استخدام SOCKS5 على المنفذ 1080

يدعم ProxyHat بروتوكول SOCKS5 على المنفذ 1080 لمن يحتاج إلى نقل بيانات أكثر مرونة دون اعتماد على رؤوس HTTP. كل من Deno و Bun يدعم SOCKS5 عبر نفس واجهة البروكسي:

// Deno + SOCKS5
const socksClient = Deno.createHttpClient({
  proxy: {
    url: "socks5://gate.proxyhat.com:1080",
    basicAuth: {
      username: "user-country-FR-session-xyz789",
      password: "pass",
    },
  },
});

const res = await fetch("https://httpbin.org/ip", { client: socksClient });
console.log(await res.json());
socksClient.close();
// Bun + SOCKS5
const res = await fetch("https://httpbin.org/ip", {
  proxy: "socks5://user-country-FR-session-xyz789:pass@gate.proxyhat.com:1080",
});
console.log(await res.json());

متغيرات البيئة HTTP_PROXY و HTTPS_PROXY ومتى تفضّل الإعداد لكل عميل

تدعم كل من Deno و Bun قراءة متغيرات البيئة HTTP_PROXY وHTTPS_PROXY في سياقات معينة. Bun، على وجه الخصوص، يقرأ هذه المتغيرات تلقائيًا عند بدء التشغيل. هذا مناسب للتطبيقات التي تريد تمرير كل الطلبات عبر نفس البروكسي:

# تعيين متغيرات البيئة
export HTTP_PROXY="http://user-country-US:pass@gate.proxyhat.com:8080"
export HTTPS_PROXY="http://user-country-US:pass@gate.proxyhat.com:8080"

# ثم تشغيل السكربت
bun run scraper.ts

لكن متغيرات البيئة تفرض بروكسي واحدًا على جميع الطلبات. إذا كنت تحتاج إلى:

  • بروكسي مختلف لكل طلب (دوران IP)،
  • استهداف جغرافي متباين بين الطلبات،
  • جلسات لاصقة لبعض الطلبات ودوران لطلبات أخرى،

فالإعداد لكل عميل (per-client config) هو الخيار الصحيح. في Deno، أنشئ كائنات createHttpClient متعددة؛ وفي Bun، مرّر proxy مختلفًا في كل استدعاء fetch.

لماذا البروكسي السكني ضروري للأهداف ذات الحظر العالي

البروكسي السكني يستخدم عناوين IP مخصصة من مزودي خدمات إنترنت حقيقيين، مما يجعل الطلبات تبدو كأنها صادرة من مستخدمين عاديين. هذا بالغ الأهمية عند استهداف مواقع تطبّق أنظمة مكافحة البوت المتقدمة، مثل منصات التواصل الاجتماعي ومواقع التجارة الإلكترونية الكبرى. الـ IP السكني يحقق معدلات نجاح تتجاوز 90% في كثير من الحالات، مقارنةً بـ 40-60% للبروكسي المُستضاف في مراكز البيانات.

البروكسي القائم على مراكز البيانات أرخص، لكن عناوينه تنتمي إلى نطاقات ASN معروفة لمزودي الاستضافة، مما يجعلها سهلة الحظر من قبل أنظمة مكافحة الاحتيال. راجع صفحة المواقع للاطلاع على تغطية ProxyHat الجغرافية.

مثال عملي: دوران مجموعة جلسات لاصقة عبر طلبات متزامنة

السيناريو: نريد استخراج بيانات من موقع يفرض حدًا على عدد الطلبات لكل IP، مع الحفاظ على جلسة لاصقة لكل عامل (worker) حتى لا يبدو السلوك آليًا جدًا. نستخدم Promise.all لإرسال طلبات متزامنة وAbortController لفرض مهلة زمنية.

// bun run rotating_sticky_sessions.ts

const PROXY_GATE = "gate.proxyhat.com:8080";
const PROXY_USER = "user";
const PROXY_PASS = "pass";
const TARGET_URL = "https://httpbin.org/ip";
const TIMEOUT_MS = 10000;

// توليد معرّفات جلسات فريدة
const sessionIds = Array.from({ length: 5 }, (_, i) => `sess-${Date.now()}-${i}`);

async function fetchWithStickySession(sessionId: string, country: string) {
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);

  const proxyUrl = `http://${PROXY_USER}-country-${country}-session-${sessionId}:${PROXY_PASS}@${PROXY_GATE}`;

  try {
    const res = await fetch(TARGET_URL, {
      proxy: proxyUrl,
      signal: controller.signal,
    });
    if (!res.ok) {
      throw new Error(`HTTP ${res.status}`);
    }
    return { sessionId, data: await res.json() };
  } catch (err) {
    console.error(`الجلسة ${sessionId} فشلت:`, err.message);
    return { sessionId, data: null, error: err.message };
  } finally {
    clearTimeout(timeout);
  }
}

// إرسال 5 طلبات متزامنة عبر جلسات وبلدان مختلفة
const countries = ["US", "DE", "GB", "FR", "JP"];
const results = await Promise.all(
  sessionIds.map((sid, i) => fetchWithStickySession(sid, countries[i]))
);

for (const r of results) {
  console.log(`الجلسة ${r.sessionId}:`, r.data ?? r.error);
}

هذا النمط يحقق 5 طلبات متزامنة عبر 5 جلسات لاصقة مختلفة، كل واحدة بـ IP من بلد مختلف. المهلة الزمنية البالغة 10 ثوانٍ تمنع التعليق إلى ما لا نهاية.

نصائح الإنتاج: إعادة المحاولة مع التراجع، شهادات CA، وإعادة استخدام الاتصالات

إعادة المحاولة مع التراجع الأُسي

في الإنتاج، ستفشل بعض الطلبات بسبب انقطاع الشبكة أو تجاوز الحد المسموح. طبّق إعادة المحاولة مع تراجع أُسي (exponential backoff) لتجنّب إغراق البروكسي بطلبات متكررة:

// deno run --allow-net retry_backoff.ts

const MAX_RETRIES = 3;
const BASE_DELAY_MS = 500;

async function fetchWithRetry(
  url: string,
  client: Deno.HttpClient,
  retries = MAX_RETRIES
): Promise<Response> {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const res = await fetch(url, { client });
      if (res.ok) return res;
      if (res.status === 429 || res.status >= 500) {
        throw new Error(`HTTP ${res.status} — قابل لإعادة المحاولة`);
      }
      return res; // أخطاء 4xx الأخرى لا تستحق إعادة المحاولة
    } catch (err) {
      if (attempt === retries) throw err;
      const delay = BASE_DELAY_MS * Math.pow(2, attempt);
      console.warn(`المحاولة ${attempt + 1} فشلت، إعادة بعد ${delay}ms`);
      await new Promise((r) => setTimeout(r, delay));
    }
  }
  throw new Error("لن يصل التنفيذ هنا");
}

const client = Deno.createHttpClient({
  proxy: {
    url: "http://gate.proxyhat.com:8080",
    basicAuth: { username: "user-country-US", password: "pass" },
  },
});

const res = await fetchWithRetry("https://httpbin.org/get", client);
console.log(await res.json());
client.close();

شهادات CA مخصصة في Deno

إذا كنت تعمل في بيئة تستخدم شهادات SSL/TLS مخصصة (مثل بروكسي مؤسسي يفحص حركة المررف)، يمكنك تمرير شهادات CA عبر خيار caCerts في Deno.createHttpClient:

const caPem = await Deno.readTextFile("./custom-ca.pem");

const client = Deno.createHttpClient({
  proxy: {
    url: "http://gate.proxyhat.com:8080",
    basicAuth: { username: "user-country-US", password: "pass" },
  },
  caCerts: [caPem],
});

const res = await fetch("https://httpbin.org/get", { client });
console.log(await res.text());
client.close();

إعادة استخدام الاتصالات

في Deno، أعد استخدام كائن Deno.HttpClient عبر طلبات متعددة بدلاً من إنشاء واحد جديد لكل طلب. هذا يقلل زمن الاستجابة بنسبة تصل إلى 200 مللي ثانية لكل طلب عن طريق تجايل مصافحة TLS. فقط تذكّر استدعاء client.close() عند الانتهاء لتحرير الموارد:

// إنشاء عميل واحد وإعادة استخدامه
const sharedClient = Deno.createHttpClient({
  proxy: {
    url: "http://gate.proxyhat.com:8080",
    basicAuth: { username: "user-country-DE-session-persistent1", password: "pass" },
  },
  // الحد الأقصى للاتصالات المخزّنة
  poolMaxSize: 20,
});

const urls = [
  "https://httpbin.org/get?page=1",
  "https://httpbin.org/get?page=2",
  "https://httpbin.org/get?page=3",
];

for (const url of urls) {
  const res = await fetch(url, { client: sharedClient });
  console.log(`${url} → ${res.status}`);
}

sharedClient.close();

مقارنة جنباً إلى جنب: الـ API الخام مقابل ProxyHat Node SDK

يوفّر ProxyHat SDK رسمي للـ Node.js يعمل تحت كل من Deno و Bun بفضل توافق وحدات npm. إليك مقارنة بين استخدام الـ API الخام والـ SDK:

// --- الطريقة 1: الـ API الخام في Bun ---
const res = await fetch("https://httpbin.org/ip", {
  proxy: "http://user-country-US-session-abc:pass@gate.proxyhat.com:8080",
});
console.log(await res.json());
// --- الطريقة 2: ProxyHat Node SDK (يعمل في Deno و Bun) ---
// npm install @proxyhat/node-sdk

import { ProxyHat } from "@proxyhat/node-sdk";

const ph = new ProxyHat({
  username: "user",
  password: "pass",
  defaultCountry: "US",
});

// الحصول على رابط بروكسي مع جلسة لاصقة
const proxyUrl = ph.getProxyUrl({
  country: "DE",
  city: "berlin",
  sessionId: "my-session-1",
  protocol: "http",
});

console.log("رابط البروكسي:", proxyUrl);
// → http://user-country-DE-city-berlin-session-my-session-1:pass@gate.proxyhat.com:8080

// في Bun:
const res = await fetch("https://httpbin.org/ip", { proxy: proxyUrl });
console.log(await res.json());

الـ SDK يبسّط بناء رابط البروكسي وإدارة الجلسات، لكنه يظل يستخدم نفس البوابة gate.proxyhat.com والمنفذ 8080. إذا كنت تريد تحكمًا كاملًا بدون تبعيات إضافية، فالـ API الخام كافٍ تمامًا.

الاعتبارات الأخلاقية والقانونية

قبل البدء في أي مشروع استخراج بيانات، ضع الآتي في الاعتبار:

  • ابدأ بالـ APIs الرسمية أولاً: إذا وفّر الموقع واجهة برمجية رسمية، فهي الخيار الأنسب قانونيًا وتقنيًا.
  • احترم robots.txt: راجع ملف robots.txt للموقع واتبع قواعده بشأن الزحف الآلي.
  • قانون CFAA في الولايات المتحدة: الاستخراج غير المصرّح به قد ينتهك قانون الاحتيال وإساءة استخدام الكمبيوتر. راجع موارد وزارة العدل الأمريكية لمزيد من التفاصيل.
  • GDPR في الاتحاد الأوروبي: استخراج بيانات شخصية لأفراد داخل الاتحاد الأوروبي يخضع للائحة العامة لحماية البيانات. راجع الموقع الرسمي للمفوضية الأوروبية.
  • استخراج البيانات العامة فقط: لا تتجاوز جدران الدخول أو تستخرج بيانات خلفية مصادقة.

البروكسي أداة محايدة تقنيًا، لكن مسؤولية الاستخدام الأخلاقي تقع على عاتق المطور. راجع حالات استخدام استخراج الويب وتتبع نتائج البحث للاطلاع على أمثلة عملية.

نقاط رئيسية

  • fetch() الأصلية في Deno و Bun لا تقرأ البروكسي افتراضيًا — استخدم Deno.createHttpClient أو خيار proxy في Bun.
  • البروكسي السكني يحقق معدلات نجاح أعلى من 90% مقابل 40-60% لبروكسي مراكز البيانات على الأهداف المحمية.
  • ترميز الاستهداف الجغرافي والجلسات في اسم المستخدم: user-country-US-session-abc123.
  • استخدم SOCKS5 على المنفذ 1080 عند الحاجة، وHTTP على المنفذ 8080 افتراضيًا.
  • أعد استخدام كائن العميل في Deno لتقليل زمن الاستجابة بنسبة تصل إلى 200 مللي ثانية.
  • طبّق إعادة المحاولة مع تراجع أُسي وAbortController للمهلة الزمنية.
  • ابدأ بالـ APIs الرسمية واحترم robots.txt وGDPR وCFAA.

جاهز للبدء؟ راجع أسعار ProxyHat واختر الخطة المناسبة لمشروعك، أو استكشف المواقع المتاحة للاستهداف الجغرافي.

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog