أصبح لدى مطوري تطبيقات صور الفعاليات الآن قائمة مرجعية ملموسة لضمان استمرار عمليات الرفع عبر المتصفح في الأماكن المزدحمة. قد ينتقل مستخدم واحد من شبكة Wi-Fi إلى البيانات الخلوية بينما تتنافس عشرات الأجهزة على نفس نقطة الاتصال (hotspot). يوضح هذا الدليل كيفية منع اختفاء الصورة بعد ظهور رسالة تنبيه "اكتمل الرفع" (upload complete toast)، حتى لو قام الضيف بقفل الهاتف أو حدث تقلب في الشبكة.
لماذا تفشل عمليات الرفع العادية في حفلات الزفاف والمهرجانات
في المكتب، يعمل الكمبيوتر المحمول عبر اتصال Ethernet مستقر وينقر مستخدم واحد على "إرسال". أما في حفل زفاف أو مهرجان موسيقي، فقد تؤدي نفس العملية إلى سلسلة من المشكلات: ينتقل الضيف من قاعة الاحتفال إلى موقف السيارات، أو ينهار أداء الراوتر تحت ضغط مئات الهواتف، أو يفقد الهاتف اتصال Wi-Fi وينتقل إلى البيانات الخلوية. قد يكون المتصفح قد أرسل كل بايت إلى الخادم، لكن الخادم لم يحفظ الملف في وحدة التخزين بعد. إذا أعلنت واجهة المستخدم (UI) عن النجاح بمجرد وصول شريط التقدم إلى 100%، فقد يقوم الضيف بحذف الصورة، مما يترك المنظم مع ملف مفقود.
التكلفة الخفية لنهج "الرفع فقط"
يتعامل النهج الساذج مع عملية الرفع كطلب HTTP POST واحد. يعمل هذا النهج عندما يكون الاتصال مستقرًا، ولكن في الشبكات المزدحمة، تضطر كل عملية انقطاع إلى إعادة إرسال الملف بالكامل من البداية. يشعر المستخدمون بالإحباط، ويحدث ارتفاع مفاجئ في استهلاك النطاق الترددي عندما تحاول عشرات الهواتف إعادة المحاولة في وقت واحد. إن تقسيم الملف إلى أجزاء (chunks) وتتبع كل جزء يزيد من التعقيد، ولكن النتيجة هي عملية نقل يمكن التنبؤ بها ومنخفضة العبء وتصمد أمام تبديل الشبكات.
بناء نظام رفع مجزأ وقابل للاستئناف
فيما يلي وصفة عملية خطوة بخطوة.
1. إنشاء معرف رفع (upload ID) قبل إرسال أي بيانات من المتصفح
قم بإنشاء معرف فريد عالميًا (UUID) محليًا وأرسله إلى الخادم كأول طلب. يسجل الخادم جلسة تحت هذا المعرف. إذا حاول المتصفح لاحقًا إعادة المحاولة بسبب انتهاء المهلة (timeout)، فسيقوم بتضمين نفس الـ UUID، مما يسمح للخادم بالتعرف على الجلسة وتجنب إدخال مكرر. هذا يجعل سير العمل "idempotent" (أي أن تكرار نفس الطلب ليس له تأثير ضار).
2. تقسيم الملف إلى أجزاء (chunks) بحجم 5 إلى 10 ميجابايت
حجم الجزء هو عملية موازنة. الأجزاء الصغيرة (أقل من 1 ميجابايت) تزيد من عدد طلبات HTTP والعبء المرتبط بالترويسات (header overhead). أما الأجزاء الكبيرة جدًا فتجعل أي انقطاع مكلفًا لأن العميل يجب أن يعيد إرسال قطعة كبيرة. بالنسبة للصور العادية ومقاطع الفيديو القصيرة، يحقق حجم 5-10 ميجابايت التوازن المطلوب: حيث تنتهي كل عملية طلب بسرعة كافية للحفاظ على استجابة واجهة المستخدم، مع بقاء عدد الطلبات ضمن نطاق يمكن إدارته.
3. تحديد عدد عمليات الرفع المتوازية
يمكن لمتصفحات الهاتف المحمول فتح اتصالات عديدة، ولكن في شبكة Wi-Fi مزدحمة، يتنافس كل تدفق إضافي على النطاق الترددي المحدود. تدفقان مستقران أفضل من ثمانية تدفقات متنافسة. استخدم واجهة برمجة التطبيقات navigator.connection لاكتشاف حالات النطاق الترددي المنخفض وتقليل التزامن (concurrency) تلقائيًا.
4. حفظ حالة الرفع في IndexedDB
قم بتخزين معرف الرفع (upload ID)، وقائمة الأجزاء التي تم إرسالها بالفعل، وأي إزاحات (offsets) أكدها الخادم في IndexedDB الخاص بالمتصفح. إذا تمت إعادة تحميل الصفحة أو أغلق المستخدم علامة التبويب، يمكن للعميل استعادة الحالة عند التحميل التالي. عندما يعيد المستخدم فتح الصفحة، اطلب منه اختيار نفس الملف؛ حيث تتيح البيانات الوصفية (metadata) المخزنة استئناف الرفع من آخر جزء تم تأكيده بدلاً من البدء من جديد.
5. اكتشاف تغييرات الشبكة الحقيقية، وليس فقط navigator.onLine
غالبًا ما تشير علامة navigator.onLine إلى أن الاتصال "متصل" حتى عندما يكون الاتصال غير قابل للاستخدام. بدلاً من ذلك، قم بتعيين مهلة طلب قصيرة (مثلاً 5 ثوانٍ) لكل جزء. إذا حدث انتهاء للمهلة، تعامل مع الشبكة على أنها مقطوعة. عندما يعود الاتصال، استعلم من الخادم عن قائمة الأجزاء التي لديه بالفعل، ثم استمر في رفع الأجزاء المفقودة فقط. هذا يمنع إرسال بيانات مكررة بعد انقطاع قصير.
6. تطبيق التراجع الأسي مع التذبذب (exponential backoff with jitter) لإعادة المحاولة
عندما تلاحظ أجهزة العديد من الضيوف عودة الشبكة، قد تقوم جميعها بإرسال محاولات إعادة الاتصال في نفس اللحظة، مما يؤدي إلى إغراق الخادم. يجعل "التراجع الأسي" (exponential backoff) كل محاولة إعادة انتظار وقت أطول من المحاولة السابقة، بينما يضيف "التذبذب" (jitter) إزاحة عشوائية صغيرة. هذا المزيج يوزع حركة مرور إعادة المحاولة على بضع ثوانٍ، مما يمنع حدوث طفرة مفاجئة.
7. عرض ملاحظات متدرجة وسهلة الوصول
يوضح شريط الحالة ثلاثي المستويات الحالة الحقيقية للملف:
- تم الاستلام (Received) – قام الخادم بتخزين كل جزء وحدد الملف على أنه مكتمل.
- جاري التحضير (Preparing) – يقوم الخادم بإنشاء الصور المصغرة (thumbnails) أو تحويل تنسيق الفيديو (transcoding).
- متاح (Available) – يمكن للمنظم عرض الملف أو تنزيله.
تجنب الاعتماد على اللون وحده؛ قم بدمج الأيقونات مع نص قصير حتى يتمكن مستخدمو قارئات الشاشة أيضًا من فهم التقدم.
ما الذي يمكن أن يسير بشكل خاطئ؟
حتى عملية الرفع القابلة للاستئناف والمصممة جيدًا قد تتعثر في بعض الحالات الاستثنائية.
ما الذي يجب مراقبته لاحقًا
منصة الويب في تطور مستمر.
الخلاصة
إن عملية الرفع المجزأة والقابلة للاستئناف، التي تتبع كل جزء، وتخزن الحالة محليًا، وتعيد المحاولة بذكاء، تحول شبكة فعاليات غير مستقرة إلى قناة موثوقة لصور الضيوف. قم بتنفيذ قائمة التحقق المذكورة أعلاه.
