عميل HTTP بلغة JavaScript: تنفيذ الطلبات بشكل صحيح - المستوى المتقدم
الطلبات الأساسية لـ HTTP باستخدام fetch أو axios ليست سوى قمة جبل الجليد. في تطبيقات الإنتاج الحقيقية على Node.js، تواجه عشرات التفاصيل الدقيقة: تجمعات الاتصالات، إعادة المحاولة عند الفشل، المعترضات لتسجيل السجلات، بث البيانات الكبيرة، وضبط المهلات بدقة. في هذه المقالة، سنستعرض التقنيات المتقدمة للعمل مع عملاء HTTP في JavaScript. ستتعلم كيفية إدارة keep-alive، تنفيذ آلية إعادة محاولة موثوقة، استخدام المعترضات، وإنشاء وكلاء مخصصين. المحتوى موجه للمطورين الذين هم على دراية بأساسيات HTTP ويريدون كتابة كود أكثر كفاءة وتحملًا للأخطاء.
1. إدارة الاتصالات: Keep-Alive والوكلاء المخصصون
افتراضيًا، يستخدم Node.js تجمعًا عالميًا لوكلاء HTTP. ومع ذلك، بالنسبة للأنظمة عالية التحميل، من المهم التحكم في عدد الاتصالات المتزامنة وإعادة استخدامها. دعنا نلقي نظرة على إعداد keep-alive باستخدام وحدة http ومكتبة undici.
مثال مع وكيل مخصص (Node.js built-in):
const http = require('http');const https = require('https');
// إنشاء وكيل مخصص مع تجمع اتصالاتconst agent = new http.Agent({ keepAlive: true, maxSockets: 50, // الحد الأقصى 50 مقبسًا متزامنًا maxFreeSockets: 10, // لا يزيد عن 10 مقابس حرة في التجمع timeout: 60000, // مهلة خمول المقبس (مللي ثانية)});
const options = { hostname: 'api.example.com', port: 80, path: '/data', agent: agent,};
const req = http.get(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => console.log('تم استلام الرد:', data));});
req.on('error', (e) => console.error('خطأ:', e.message));النهج الحديث مع undici (أسرع وأخف):
const { Client, Pool } = require('undici');
// إنشاء تجمع مع keep-aliveconst client = new Pool('https://api.example.com', { connections: 100, pipelining: 10, keepAliveTimeout: 30000,});
// تنفيذ الطلبclient.request({ method: 'GET', path: '/data',}).then(({ statusCode, body }) => { console.log('الحالة:', statusCode); body.setEncoding('utf8'); body.on('data', console.log);}).catch(err => console.error(err));استخدام الوكلاء المخصصين يساعد في تجنب مشاكل تسرب المقابس ويحسن الأداء من خلال إعادة استخدام الاتصالات.
2. آلية موثوقة لإعادة المحاولة (Retry)
الشبكات غير مستقرة. حتى الأعطال المؤقتة يمكن أن تؤدي إلى فقدان البيانات. يجب أن تأخذ استراتيجية إعادة المحاولة الصحيحة في الاعتبار نوع الخطأ وعدد المحاولات والتأخير الأسي. سنقوم بتنفيذ مصمم إعادة محاولة عالمي لأي عميل HTTP.
const axios = require('axios');const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function withRetry(requestFn, retries = 3, baseDelay = 1000) { for (let attempt = 1; attempt <= retries; attempt++) { try { return await requestFn(); } catch (error) { // لا نعيد المحاولة على أخطاء العميل (4xx) if (error.response && error.response.status >= 400 && error.response.status < 500) { throw error; } if (attempt === retries) { throw error; // استنفذت جميع المحاولات } const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000; console.log(`المحاولة ${attempt} فشلت. ننتظر ${delay}ms...`); await sleep(delay); } }}
// الاستخدامasync function fetchData() { const response = await withRetry(() => axios.get('https://api.example.com/data'), 5, 500); return response.data;}
fetchData().then(console.log).catch(console.error);النقاط الرئيسية: استثناء أخطاء 4xx-