أحداث يرسلها الخادم (Server-Sent Events) في TypeScript: دليل خطوة بخطوة للمشاريع الحقيقية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

أحداث يرسلها الخادم (Server-Sent Events) في TypeScript: بث البيانات بدون صداع

\n\n

تخيل: خادمك يولد بيانات — سجلات، إشعارات، تحديثات أسعار العملات — ويجب إرسالها فوراً إلى الواجهة الأمامية. WebSocket؟ قوي لكنه مبالغ فيه. Polling؟ بطيء ويستهلك النطاق الترددي. هناك طريق ثالث — أنيق، بسيط ومفيد بشكل لا يصدق: أحداث يرسلها الخادم (SSE).

\n\n

في هذه المقالة، سنشرح SSE باستخدام TypeScript من الألف إلى الياء. سنكتب العميل والخادم، ونتعلم كيفية معالجة الأخطاء وإعادة الاتصال، والأهم من ذلك، سنفهم متى يكون SSE أفضل من الطرق الأخرى. هيا بنا!

\n\n

ما هي أحداث يرسلها الخادم (Server-Sent Events) ولماذا نحتاجها؟

\n\n

أحداث يرسلها الخادم هي معيار HTML5 يسمح للخادم بإرسال البيانات إلى العميل عبر اتصال HTTP واحد في الوقت الفعلي. على عكس WebSocket، فإن SSE أحادي الاتجاه: الخادم فقط هو من يرسل الرسائل. ولكن في هذا تكمن قوته — فهو بسيط للغاية ولا يتطلب مكتبات إضافية.

\n\n

متى تختار SSE؟

\n\n
    \n
  • البث أحادي الاتجاه: الإشعارات، السجلات، أسعار العملات، مؤشرات الأسهم.
  • \n
  • تكامل بسيط: يعمل عبر EventSource القياسي في المتصفح — لا حاجة لحزم npm.
  • \n
  • إعادة اتصال تلقائية: المتصفح يعيد الاتصال تلقائياً عند انقطاعه.
  • \n
  • التوافق مع HTTP/2: تعدد الإرسال لا يتعارض، على عكس WebSocket.
  • \n
\n\n

لكن تذكر: SSE لا يمكنه إرسال بيانات من العميل إلى الخادم (استخدم طلبات POST العادية لذلك) ولا يدعم في المتصفحات القديمة (مرحباً IE).

\n\n

جزء الخادم: كتابة SSE باستخدام TypeScript + Express

\n\n

لنبدأ من الواجهة الخلفية. سننشئ خادماً بسيطاً باستخدام Node.js مع Express و TypeScript. قم بتثبيت التبعيات:

\n\n
npm init -y\nnpm install express cors\nnpm install -D typescript @types/express @types/node ts-node\nnpx tsc --init
\n\n

الآن لنكتب الخادم نفسه. النقطة الأساسية هي تعيين الرؤوس الصحيحة وتنسيق الرسائل.

\n\n
// server.ts\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\n\n// نقطة النهاية لـ SSE\napp.get('/events', (req: Request, res: Response) => {\n  // تعيين رؤوس SSE\n  res.writeHead(200, {\n    'Content-Type': 'text/event-stream',\n    'Cache-Control': 'no-cache',\n    'Connection': 'keep-alive',\n  });\n\n  // إرسال رسالة أولية\n  res.write('data: {"message": "تم إنشاء الاتصال"}\\n\\n');\n\n  // إرسال حدث كل 3 ثوانٍ\n  const intervalId = setInterval(() => {\n    const data = JSON.stringify({\n      time: new Date().toISOString(),\n      value: Math.random() * 100,\n    });\n    res.write(`data: ${data}\\n\\n`);\n  }, 3000);\n\n  // معالجة فصل العميل\n  req.on('close', () => {\n    clearInterval(intervalId);\n    res.end();\n    console.log('تم فصل العميل');\n  });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`خادم SSE يعمل على المنفذ ${PORT}`));
\n\n

لاحظ التنسيق: كل رسالة تبدأ بـ data: وتنتهي بسطرين جديدين \\n\\n. يمكنك أيضاً تحديد id و event و retry — لكن هذا هو الأساس.

\n\n

إرسال أحداث مسماة

\n\n

أحياناً تحتاج إلى تمييز أنواع الرسائل. أضف حقل event:

\n\n
res.write('event: update\\n');\nres.write(`data: ${JSON.stringify({ id: 1, title: 'منشور جديد' })}\\n\\n`);\n\n// ثم — حدث آخر\nres.write('event: notification\\n');\nres.write('data: {"level": "info", "text": "الخادم يعمل"}\\n\\n');
\n\n

على العميل، سنتمكن من الاشتراك في أحداث محددة.

\n\n

جزء العميل: استقبال الأحداث باستخدام TypeScript

\n\n

الآن لنكتب العميل. في المتصفح، يتم استخدام EventSource المدمج. ولكن إذا

المدونات

توصيات الكتب