توسعهدهندگان اپلیکیشنهای عکسِ رویداد، اکنون یک چکلیست مشخص برای زنده نگه داشتن آپلودهای مرورگر در مکانهای شلوغ دارند. یک کاربر ممکن است از Wi-Fi به شبکه سلولار سوئیچ کند، در حالی که دهها دستگاه برای استفاده از یک هاتسپات واحد رقابت میکنند. این راهنما نشان میدهد که چگونه میتوان از ناپدید شدن یک عکس پس از نمایش پیام «آپلود کامل شد» جلوگیری کرد، حتی اگر مهمان گوشی خود را قفل کند یا شبکه دچار اختلال شود.
چرا آپلودهای معمولی در عروسیها و جشنوارهها با شکست مواجه میشوند
در یک محیط اداری، لپتاپ به یک اتصال اترنت پایدار متصل است و یک کاربر تنها روی دکمه «ارسال» کلیک میکند. اما در یک جشن عروسی یا یک جشنواره موسیقی، همین اقدام میتواند زنجیرهای از مشکلات را ایجاد کند: مهمان از سالن مراسم به سمت پارکینگ حرکت میکند، روتر زیر بار صدها گوشی از کار میافتد، یا گوشی اتصال Wi-Fi را از دست داده و به شبکه سلولار سوئیچ میکند. ممکن است مرورگر تمام بایتها را به سرور ارسال کرده باشد، اما سرور هنوز فایل را در حافظه ذخیره نکرده است. اگر رابط کاربری (UI) دقیقاً در لحظهای که نوار پیشرفت به ۱۰۰٪ رسید، پیام موفقیت را نمایش دهد، ممکن است مهمان عکس را پاک کند و برگزارکننده با یک فایل مفقود شده روبرو شود.
هزینه پنهانِ رویکرد «فقط آپلود کن»
یک رویکرد سادهلوحانه، آپلود را به عنوان یک درخواست واحد HTTP POST در نظر میگیرد. این روش زمانی که اتصال پایدار است کار میکند، اما در یک شبکه پرترافیک، هر بار قطع شدن اتصال باعث میشود کل فایل از ابتدا ارسال شود. کاربران کلافه میشوند و وقتی دهها گوشی همزمان تلاش مجدد میکنند، پهنای باند به شدت اشغال میشود. تقسیم فایل به تکههای کوچک (chunks) و ردیابی هر قطعه، پیچیدگی کار را افزایش میدهد، اما پاداش آن یک انتقال قابل پیشبینی و با سربار کم است که در برابر تغییرات شبکه دوام میآورد.
ساخت یک سیستم آپلود تکهتکه و قابل ادامه (Resumable)
در ادامه یک دستورالعمل عملی و مرحلهبهمرحله آورده شده است.
۱. قبل از خروج هرگونه داده از مرورگر، یک شناسه آپلود ایجاد کنید
یک شناسه منحصربهفرد جهانی (UUID) به صورت محلی ایجاد کنید و آن را به عنوان اولین درخواست به سرور بفرستید. سرور یک نشست (session) را تحت آن شناسه ثبت میکند. اگر مرورگر بعداً به دلیل اتمام زمان (timeout)، دوباره تلاش کرد، همان UUID را ارسال میکند که باعث میشود سرور نشست را شناسایی کرده و از ایجاد ورودی تکراری جلوگیری کند. این کار جریان کاری را idempotent میکند؛ یعنی تکرار یک درخواست یکسان، اثر منفی نخواهد داشت.
۲. فایل را به تکههای ۵ تا ۱۰ مگابایتی تقسیم کنید
اندازه هر تکه (chunk) یک سبکسنگین کردن است. تکههای کوچک (زیر ۱ مگابایت) تعداد درخواستهای HTTP و سربار هدرهای مربوطه را افزایش میدهند. تکههای بسیار بزرگ باعث میشوند هر بار قطع شدن اتصال پرهزینه باشد، زیرا کلاینت باید بخش بزرگی را دوباره ارسال کند. برای عکسهای معمولی و ویدیوهای کوتاه، اندازه ۵ تا ۱۰ مگابایت تعادل مناسبی ایجاد میکند: هر درخواست به اندازه کافی سریع تمام میشود تا رابط کاربری پاسخگو بماند، و در عین حال تعداد درخواستها نیز قابل مدیریت است.
۳. تعداد آپلودهای موازی را محدود کنید
مرورگرهای موبایل میتوانند اتصالات زیادی باز کنند، اما در یک شبکه Wi-Fi شلوغ، هر جریان اضافی برای پهنای باند محدود رقابت میکند. دو جریان پایدار بهتر از هشت جریان رقیب هستند. از API navigator.connection برای تشخیص شرایط پهنای باند پایین و کاهش خودکار همزمانی (concurrency) استفاده کنید.
۴. وضعیت آپلود را در IndexedDB ذخیره کنید
شناسه آپلود، لیست تکههای ارسال شده و هرگونه آفست (offset) تایید شده توسط سرور را در IndexedDB مرورگر ذخیره کنید. اگر صفحه بازنشانی (reload) شود یا کاربر تب را ببندد، کلاینت میتواند در بارگذاری بعدی وضعیت را بازیابی کند. وقتی کاربر دوباره صفحه را باز میکند، از او بخواهید همان فایل را انتخاب کند؛ متادیتای ذخیره شده اجازه میدهد آپلود به جای شروع از ابتدا، از آخرین تکه تایید شده ادامه یابد.
۵. تغییرات واقعی شبکه را تشخیص دهید، نه فقط navigator.onLine را
پرچم navigator.onLine اغلب حتی زمانی که اتصال غیرقابل استفاده است، وضعیت را «online» گزارش میدهد. در عوض، برای هر تکه یک زمان انتظار (timeout) کوتاه (مثلاً ۵ ثانیه) تعیین کنید. اگر تایماوت رخ داد، شبکه را قطع در نظر بگیرید. وقتی اتصال برقرار شد، از سرور لیست تکههایی که قبلاً دریافت کرده است را بپرسید و سپس فقط قطعات مفقود را آپلود کنید. این کار از ارسال دادههای تکراری پس از یک قطعی کوتاه جلوگیری میکند.
۶. برای تلاشهای مجدد از Exponential Backoff همراه با Jitter استفاده کنید
وقتی دستگاههای بسیاری از مهمانها متوجه بازگشت شبکه میشوند، ممکن است همگی در یک لحظه درخواست مجدد بفرستند و سرور را از کار بیندازند. روش Exponential Backoff باعث میشود هر تلاش مجدد نسبت به تلاش قبلی زمان بیشتری منتظر بماند، در حالی که Jitter یک اختلاف زمانی تصادفی و کوچک اضافه میکند. این ترکیب، ترافیک تلاش مجدد را در طول چند ثانیه پخش میکند و از ایجاد اوج ناگهانی ترافیک (spike) جلوگیری میکند.
۷. بازخوردهای لایهبندی شده و قابل دسترس نمایش دهید
یک نوار وضعیت سه مرحلهای، وضعیت واقعی فایل را اعلام میکند:
- Received – سرور تمام تکهها را ذخیره کرده و فایل را به عنوان کامل علامتگذاری کرده است.
- Preparing – سرور در حال تولید تصاویر بندانگشتی (thumbnails) یا تبدیل فرمت (transcoding) ویدیو است.
- Available – برگزارکننده میتواند فایل را مشاهده یا دانلود کند.
تنها به رنگ تکیه نکنید؛ آیکونها را با متنهای کوتاه همراه کنید تا کاربران صفحهخوان نیز وضعیت پیشرفت را درک کنند.
چه مشکلاتی ممکن است همچنان پیش بیاید؟
حتی یک آپلود قابلادامه (resumable upload) که به خوبی مهندسی شده باشد نیز ممکن است در چند مورد خاص (edge cases) دچار مشکل شود.
در مرحله بعد به چه نکاتی توجه کنیم
پلتفرم وب در حال تکامل است.
نتیجهگیری
یک آپلود قابلادامه و تکهتکه (chunked upload) که هر بخش را ردیابی میکند، وضعیت را بهصورت محلی ذخیره میکند و هوشمندانه تلاش مجدد انجام میدهد، یک شبکه رویداد ناپایدار را به مسیری قابلاعتماد برای عکسهای مهمان تبدیل میکند. چکلیست بالا را پیادهسازی کنید.
