טיפול בבקשות טווח של קובץ שירות (service worker)

מוודאים שה-Service Worker יודע מה לעשות כשמתבקשים מענה חלקי.

בקשות HTTP מסוימות מכילות כותרת Range:, שמציינת שיש להחזיר רק חלק מהמשאב המלא. הם משמשים בדרך כלל לסטרימינג של תוכן אודיו או וידאו כדי לאפשר טעינה של קטעי מדיה קטנים יותר על פי דרישה, במקום לבקש את כל הקובץ המרוחק בבת אחת.

קובץ שירות (service worker) הוא קוד JavaScript שנמצא בין אפליקציית האינטרנט לרשת, ויכול ליירט בקשות רשת יוצאות וליצור תשובות אליהן.

בעבר, בקשות טווח ו-service worker לא שיחקו היטב ביחד. היה צורך לנקוט צעדים מיוחדים כדי למנוע תוצאות לא נעימות בקובץ השירות (service worker). למרבה המזל, המצב הזה מתחיל להשתנות. בדפדפנים עם ההתנהגות הנכונה, בקשות טווח "פועלות" "פשוט" כאשר הן עוברות דרך קובץ שירות (service worker).

מה הבעיה?

צריך להשתמש ב-Service Worker עם פונקציית ההאזנה fetch הבאה, שלוקחת כל בקשה נכנסת ומעבירה אותה לרשת:

self.addEventListener('fetch', (event) => {
  // The Range: header will not pass through in
  // browsers that behave incorrectly.
  event.respondWith(fetch(event.request));
});

בדפדפנים עם התנהגות לא נכונה, אם הכותרת event.request תכלול כותרת Range:, היא תוסר באופן שקט. הבקשה שהתקבלה על ידי השרת המרוחק לא תכלול כלל את Range:. הפעולה הזו לא בהכרח "תשבש" כלום, כי לשרת מותר מבחינה טכנית להחזיר את גוף התגובה המלא, עם קוד סטטוס 200, גם אם הבקשה המקורית כוללת כותרת Range:. אבל היא תוביל להעברת נתונים רבים יותר מהנדרש אך ורק מבחינת הדפדפן.

מפתחים שהיו מודעים להתנהגות הזו יכולים לעקוף אותה על ידי בדיקה מפורשת של הנוכחות של כותרת Range:, ולא ביצוע קריאה ל-event.respondWith() אם היא קיימת. באופן כזה, קובץ השירות (service worker) מסיר את עצמו בפועל מתמונת יצירת התגובות, ובמקום זאת נעשה שימוש בלוגיקת ברירת המחדל של הרשת של הדפדפן, שיודעת לשמור בקשות לטווח.

self.addEventListener('fetch', (event) => {
  // Return without calling event.respondWith()
  // if this is a range request.
  if (event.request.headers.has('range')) {
    return;
  }

  event.respondWith(fetch(event.request));
});

עם זאת, ניתן לומר שרוב המפתחים לא היו מודעים לצורך לעשות זאת. לא היה ברור למה צריך לעשות את זה. בסופו של דבר, ההגבלה הזאת נבעה מדפדפנים שצריכים להתעדכן בשינויים במפרט הבסיסי, ונוספו תמיכה בפונקציונליות הזו.

מה תוקן?

דפדפנים שמתנהגים באופן תקין שומרים על הכותרת Range: כשמעבירים את event.request אל fetch(). כלומר, קוד ה-Service Worker בדוגמה הראשונית שלי יאפשר לשרת המרוחק לראות את הכותרת Range:, אם הוא הוגדר על ידי הדפדפן:

self.addEventListener('fetch', (event) => {
  // The Range: header will pass through in browsers
  // that behave correctly.
  event.respondWith(fetch(event.request));
});

כעת השרת יכול לטפל כראוי בבקשת הטווח ולהחזיר תגובה חלקית עם קוד הסטטוס 206.

אילו דפדפנים פועלים בצורה תקינה?

בגרסאות האחרונות של Safari יש פונקציונליות נכונה. Chrome ו-Edge, החל מגרסה 87, יפעלו גם הם באופן תקין.

נכון לאוקטובר 2020, התנהגות זו עדיין לא נפתרה ב-Firefox, כך שיכול להיות שעדיין תצטרכו להתחשב בהתנהגות הזו בזמן פריסת הקוד של קובץ השירות (service worker) בסביבת הייצור.

הדרך הטובה ביותר לבדוק אם דפדפן מסוים תיקן את ההתנהגות הזו, בדוק את השורה 'הכללת כותרת הטווח בבקשת הרשת' במרכז הבקרה לבדיקות של פלטפורמת אינטרנט.

מה לגבי הצגת בקשות לטווח מהמטמון?

קובצי שירות (service worker) יכולים לעשות הרבה יותר מאשר רק להעביר בקשה לרשת. אחד מהתרחישים הנפוצים הוא להוסיף משאבים, כמו קובצי אודיו ווידאו, למטמון מקומי. לאחר מכן, קובץ שירות (service worker) יכול למלא בקשות מהמטמון, תוך עקיפת הרשת לחלוטין.

כל הדפדפנים, כולל Firefox, תומכים בבדיקת בקשה בתוך handler של fetch, בדיקה אם יש כותרת Range: ואז מילוי הבקשה באופן מקומי באמצעות תגובה 206 שמגיעה ממטמון. עם זאת, הקוד של קובץ השירות (service worker) לניתוח תקין של הכותרת Range: ולהחזיר רק את הקטע המתאים של התגובה המלאה שנשמרה במטמון אינו טריוויאלי.

למרבה המזל, מפתחים שרוצים לקבל עזרה יכולים להיעזר ב-Workbox – קבוצת ספריות שמפשטות תרחישים נפוצים של Service Worker. הקוד workbox-range-request module מיישם את כל הלוגיקה הנדרשת להצגת תשובות חלקיות ישירות מהמטמון. במסמכי התיעוד של Workbox תוכלו למצוא מתכון מלא של התרחיש לדוגמה הזה.

התמונה הראשית בפוסט הזו היא של נטלי ריגס בתוכנית UnFlood.