SSE (Server-Sent Events) — هو معيار W3C يسمح للخادم بإرسال بيانات الدفق إلى العميل من خلال اتصال HTTP واحد في وضع أحادي الاتجاه. بالمقارنة مع WebSocket، يعمل SSE فوق HTTP العادي ولا يتطلب بروتوكولاً خاصاً أو مكتبة على جانب العميل. وفقًا لمواصفة W3C HTML Living Standard (2025)، فإن واجهة EventSource API مدعومة في جميع المتصفحات الحديثة، بما في ذلك Chrome، Firefox، Safari و Edge.
النقاط الرئيسية
SSE (Server-Sent Events) — هي تقنية تسمح لخادم الويب بإرسال البيانات إلى العميل في أي وقت بعد إنشاء الاتصال. وقد تم توحيدها من قبل WHATWG كجزء من HTML Living Standard وتستخدم نوع MIME text/event-stream. تدعم SSE نقل البيانات النصية مع إمكانية تحديد معرف الرسالة، نوع الحدث وتأخير إعادة الاتصال.
بالمقارنة مع WebSocket، الذي يتطلب بروتوكولاً ثنائي الاتجاه وطلب ترقية، يعمل SSE فوق HTTP العادي. يقوم الخادم بتعيين ترويسة Content-Type: text/event-stream، ويرسل البيانات على أجزاء ويبقي الاتصال مفتوحًا. يتلقى العميل البيانات عبر واجهة EventSource للمتصفح، والتي تقوم تلقائيًا بتحليل الدفق وإنشاء الأحداث.
وفقًا لCanIUse (2025)، فإن واجهة EventSource API مدعومة في 97.5% من المتصفحات عالميًا. وهي غير مدعومة في Internet Explorer وبعض متصفحات الجوال (Samsung Internet قبل الإصدار 7.0). ولهذه الحالات، توجد polyfills تقوم بمحاكاة EventSource عبر XHR streaming. لا يعمل SSE مع HTTP/1.1 pipelining، ولكنه متوافق تمامًا مع HTTP/2 server push.
SSE تم اقتراحه كجزء من مواصفة HTML5 في عام 2009 تحت اسم Server-Sent DOM Events. ظهر أول تطبيق في Opera 9.0، ثم في Firefox 6.0 (2011)، Chrome 9.0 (2011) و Safari 5.0 (2010). في عام 2015، تم نقل المواصفة إلى قسم منفصل من HTML Living Standard. على الرغم من تاريخ يمتد لعقود، لا يزال SSE أقل شهرة من WebSocket بسبب طبيعته أحادي الاتجاه.
آلية عمل SSE هي كالآتي: يقوم العميل بإنشاء مثال EventSource مع URL نقطة نهاية الخادم. يرسل المتصفح طلب GET مع ترويسة Accept: text/event-stream. يستجيب الخادم بحالة 200 OK وترويسة Content-Type: text/event-stream، ثم يبدأ في إرسال البيانات بتنسيق event-stream. يظل الاتصال مفتوحًا حتى يرسل الخادم إشارة إنهاء أو يقوم العميل باستدعاء close().
على جانب الخادم، يتم إرسال البيانات على أجزاء (chunked transfer encoding). كل جزء بيانات هو رسالة نصية تتكون من سطور حقول (event, data, id, retry). يمكن للخادم إرسال الرسائل في أي وقت، مما يجعل SSE مثاليًا للإشعارات وتحديثات الحالة. لا يتطلب الاتصال تبادلاً مستمرًا لحزم الحياة (heartbeat) مثل WebSocket، وإن كان حقل retry يتحكم في تكرار إعادة الاتصال.
وفقًا لاختبارات الأداء (2024)، يوفر SSE إعدادية تصل إلى 10 000 رسالة في الثانية لكل اتصال بحجم رسالة يبلغ 256 بايت. على جانب الخادم، يستهلك كل اتصال SSE تقريبًا 5–10 كبايت من الذاكرة، مما يسمح لخادم واحد بدعم أكثر من 50 000 اتصال متزامن مع 1 جيجابايت من RAM. هذا أقل بكثير من WebSocket بسبب عدم وجود بروتوكول ثنائي.
تنسيق text/event-stream — هو بروتوكول نصي بسيط حيث تتكون كل رسالة من حقول مسماة مفصولة بأحرُف السطر الجديد. كل حقل له تنسيق «اسم الحقل: القيمة». تفصل الرسائل بحرفي سطر جديد (\n\n).
الحقول المدعومة: event (نوع الحدث، الإفتراضي message)، data (سلسلة بيانات، يمكن أن تكون متعددة الأسطر)، id (آخر معرف حدث، يتم تخزينه في Last-Event-ID)، retry (وقت إعادة الاتصال بالملي ثانية). تبدأ التعليقات بنقطة (ويتم تجاهلها بواسطة المحلل، ولكن يمكن استخدامها للحفاظ على الاتصال heartbeat).
| الحقل | إلزامي | الغرض |
|---|---|---|
| event | لا | نوع الحدث (message افتراضيًا) |
| data | نعم | سلسلة بيانات الرسالة |
| id | لا | معرف الحدث لـ Last-Event-ID |
| retry | لا | تأخير إعادة الاتصال بالملي ثانية |
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001
event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000
event: close
data: Session ended
EventSource API — هي واجهة متصفح مبنية لاستقبال SSE. لإنشاء اتصال، يكفي استدعاء الباني مع URL نقطة النهاية. يقوم EventSource تلقائيًا بإنشاء الاتصال، ومعالجة إعادة الاتصال وتحليل الرسائل الواردة إلى أحداث JavaScript.
أحداث EventSource: open (تم إنشاء الاتصال)، message (تم استلام رسالة دون تحديد حدث)، error (خطأ في الاتصال). للأحداث المخصصة (event: custom)، يمكنك استخدام addEventListener مع اسم الحدث. يرسل EventSource تلقائيًا ترويسة Last-Event-ID عند إعادة الاتصال، مما يسمح للخادم باستئناف الدفق من حيث تم انقطاعه.
وفقًا لوثائق MDN (2025)، يدعم EventSource CORS ونقل بيانات الاعتماد (withCredentials). EventSource غير مناسب لإرسال ترويسات مخصصة أو هياكل الطلب — يتطلب تنفيذًا يدويًا عبر fetch + ReadableStream. لا يدعم EventSource البيانات الثنائية — يدعم النص و JSON فقط.
const eventSource = new EventSource('/api/events/stream');
eventSource.addEventListener('open', () => {
console.log('تم فتح اتصال SSE');
});
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('تم الاستلام:', data);
renderUpdate(data);
});
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
showNotification(notification.text);
});
eventSource.addEventListener('error', (error) => {
console.error('خطأ SSE:', error);
// يقوم المتصفح بإعادة الاتصال تلقائيًا
});
// إغلاق الاتصال
eventSource.close();
SSE و WebSocket — تقنيتان مختلفتان للاتصال في الوقت الحقيقي، كل منهما له نقاط قوة خاصة به. WebSocket مناسب للتبادل الثنائي للبيانات (الدردشة، الألعاب، التحرير التعاوني)، بينما SSE للتدفقات أحادية الاتجاه من الخادم إلى العميل (الإشعارات، خلاصات الأخبار، الشاشات المتحركة).
الفرق الرئيسي هو أن WebSocket يتطلب طلب ترقية من HTTP/1.1 إلى بروتوكول WebSocket (ws://)، والذي قد يتم حظره بواسطة البروكسيات المؤسسية. يعمل SSE عبر HTTP العادي، يمر عبر أي بروكسي ولا يتطلب تكويناً خاصًا للخادم. SSE أيضًا أبسط في التنفيذ — لا يحتاج الخادم إلى مكتبة إضافية، فقط تكوين استجابة HTTP بشكل صحيح.
وفقًا لاختبارات المقارنة (2024)، في عملية خادم واحدة، يدعم SSE عددًا أكبر بنسبة 30–50% من الاتصالات مقارنة بـ WebSocket بسبب البروتوكول الأبسط. ولكن لدى SSE زمن استجابة أعلى (50–200 ملي ثانية مقابل 10–50 ملي ثانية لـ WebSocket) لأن SSE يستخدم HTTP المجزأ بدلاً من دفق ثنائي الاتجاه كامل مع إطارات ثنائية.
| الخاصية | SSE | WebSocket |
|---|---|---|
| الاتجاه | خادم → عميل | ثنائي الاتجاه |
| البروتوكول | HTTP (text/event-stream) | ws:// / wss:// (RFC 6455) |
| المتصفحات | 97.5% (EventSource مبني) | 97% (WebSocket مبني) |
| البيانات | نص / JSON فقط | نص + ثنائي (Blob, ArrayBuffer) |
| معالجة البروكسي | يمر عبر أي بروكسي | يتطلب تكوين البروكسي |
| إعادة الاتصال | تلقائية (المتصفح) | تنفيذ يدوي |
| السجل | Last-Event-ID | لا وجود سجل مبني |
تنفيذ SSE على الخادم لا يتطلب مكتبات — يكفي تعيين ترويسات HTTP الصحيحة وإرسال البيانات بتنسيق text/event-stream. دعنا نلقي نظرة على مثال في Node.js باستخدام وحدة http المبنية. يقوم الخادم بتعيين ترويسات Content-Type و Cache-Control، ثم يرسل الرسائل كل N ثانية.
وفقًا لMDN Web Docs (2025)، الترويسات المطلوبة لـ SSE هي: Content-Type: text/event-stream، Cache-Control: no-cache و Connection: keep-alive. بدون Cache-Control، قد يقوم المتصفح بتخزين دفق SSE مؤقتًا، مما سيوقف التسليم. Connection: keep-alive يخبر المتصفح صراحة بإبقاء الاتصال مفتوحًا.
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let eventId = 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`event: update\n`);
res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
}).listen(3000);
from flask import Response, Flask
import time
import json
app = Flask(__name__)
@app.route('/stream')
def stream():
def generate():
event_id = 0
while True:
event_id += 1
data = json.dumps(
{'ticker': 'AAPL', 'price': 150.25})
yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
time.sleep(1)
return Response(generate(),
mimetype='text/event-stream')
استخدام SSE في التطبيقات المحمولة محدود بسبب عدم وجود تطبيق أصلي لـ EventSource لنظمي iOS و Android. على المنصات المحمولة، يتم تنفيذ SSE من خلال مكتبات خارجية: على iOS — عبر URLSession مع NSURLProtocol، على Android — عبر OkHttp مع دعم SSE (okhttp-sse). لـ React Native و Flutter، توجد حزم تقوم بمحاكاة EventSource.
على iOS، التنفيذ الأصلي لـ SSE ممكن عبر URLSessionDataDelegate. عند استلام البيانات في الطريقة urlSession(_:dataTask:didReceive:)، تقوم التطبيق بتجميع البيانات في مخزن مؤقت وتحليل تنسيق event-stream يدويًا. وفقًا لمدونة تطوير iOS (2024)، استهلاك البطارية مع SSE على iOS أقل بنسبة 40% مقارنة باتصال WebSocket المستمر بسبب عدم وجود حزم heartbeat.
على Android، يوفر OkHttp الفئة EventSource.Factory للاشتراك في تدفقات SSE. يمكن لتطبيقات Android استخدام SSE للإشعارات عندما يكون FCM غير متاح، أو لمزامنة البيانات في الخلفية. يعمل SSE على Android بشكل جيد مع WorkManager للمهام الخلفية طويلة العمر. وفقًا لوثائق OkHttp (2025)، يدعم okhttp-sse إعادة الاتصال تلقائيًا مع مستمع مخصص.
الأسئلة الشائعة
SSE — نقل أحادي الاتجاه (خادم → عميل) عبر HTTP، لا يتطلب مكتبات على العميل. WebSocket — نقل ثنائي الاتجاه مع بروتوكول ثنائي. SSE أبسط في التنفيذ، WebSocket مناسب للمهام حيث يرسل العميل البيانات أيضًا.
لا، SSE ينقل فقط البيانات النصية. للبيانات الثنائية (الصور، الصوت)، يلزم تشفير Base64، والذي يزيد الحجم بنسبة 33%. للتدفقات الثنائية، من الأفضل استخدام WebSocket.
EventSource يعيد الاتصال تلقائيًا عند حدوث انقطاع. يتم تعيين وقت التأخير عبر حقل retry في الدفق (افتراضيًا 1000 ملي ثانية). عند إعادة الاتصال، يرسل المتصفح ترويسة Last-Event-ID، مما يسمح للخادم باستئناف الدفق من حيث تم انقطاعه.
كل متصفح له حد لعدد اتصالات HTTP المتزامنة مع نطاق واحد. لـ HTTP/1.1 — 6–8 اتصالات لكل نطاق، لـ HTTP/2 — حتى 100. يستخدم SSE اتصالاً واحدًا، لذا لا يوجد منافسة مع الطلبات الأخرى.
SSE مناسب فقط لاستقبال الرسائل (الواردة). لإرسال الرسائل (الصادرة)، يلزم طلب HTTP منفصل (POST). للدردشة الكاملة، من الأفضل استخدام WebSocket أو Socket.IO مع اتصال ثنائي الاتجاه واحد.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.