ניתוב תיבת עבודה

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

workbox-routing הוא מודול שמאפשר "לנתב" בקלות הבקשות האלה פונקציות שונות שמספקות תשובות.

איך מתבצע הניתוב

כשבקשת רשת גורמת לאירוע אחזור של Service Worker, workbox-routing ינסה להגיב לבקשה באמצעות המסלולים ורכיבי ה-handler שסופקו.

תרשים ניתוב של תיבת העבודה

הנקודות העיקריות שכדאי לשים לב אליהן הן:

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

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

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

התאמה וטיפול במסלולים

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

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

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

const matchCb = ({url, request, event}) => {
  return url.pathname === '/special/url';
};

כדי לטפל ברוב תרחישי השימוש, ניתן לבחון או לבדוק את url או את request.

א' פונקציית הקריאה החוזרת של ה-handler יקבלו ExtendableEvent, Request, וגם URL אובייקט וגם ערך params, שהוא הערך שהוחזר על ידי "match" מותאמת אישית.

const handlerCb = async ({url, request, event, params}) => {
  const response = await fetch(request);
  const responseBody = await response.text();
  return new Response(`${responseBody} <!-- Look Ma. Added Content. -->`, {
    headers: response.headers,
  });
};

ה-handler צריך להחזיר הבטחה שמסתיימת ל-Response. כאן נשתמש בדוגמה הזאת, async ו-await. מתחת למכסה הקדמי, הערך המוחזר של Response יהיה מוקף בהבטחה.

אפשר לרשום את הקריאות החוזרות האלה, למשל:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

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

בדרך כלל ה-handler (המטפל) ייעשה שימוש באחת מהאסטרטגיות שצוינו ב-callback לפי אסטרטגיות תיבת עבודה כמו:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';

registerRoute(matchCb, new StaleWhileRevalidate());

בדף הזה נתמקד בנושא workbox-routing אבל אפשר מידע נוסף על האסטרטגיות האלה בנושא אסטרטגיות של תיבות עבודה

איך לרשום נתיב של ביטוי רגולרי

שיטה נפוצה היא להשתמש בביטוי רגולרי במקום ב'התאמה' קריאה חוזרת. בעזרת Workbox, קל להטמיע את הקוד בצורה הבאה:

import {registerRoute} from 'workbox-routing';

registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);

לבקשות מאת אותו מקור, הביטוי הרגולרי הזה יתאים כל עוד כתובת ה-URL של הבקשה תואמת ביטוי רגולרי.

  • https://example.com/styles/main.css
  • https://example.com/styles/nested/file.css
  • https://example.com/nested/styles/directory.css

עם זאת, בבקשות ממקורות שונים, ביטויים רגולריים חייב להיות תואם לתחילת כתובת ה-URL. הסיבה לכך היא לא סביר להניח שעם הביטוי הרגולרי new RegExp('/styles/.*\\.css') שהתכוונתם להתאים לקובצי CSS של צד שלישי.

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

אם רצית התנהגות כזו, צריך רק לוודא שההתנהגות תואם להתחלה של כתובת ה-URL. אם אנחנו רוצים להתאים עבור https://cdn.third-party-site.com, נוכל להשתמש new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css').

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

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

איך לרשום מסלול ניווט

אם האתר הוא אפליקציה שכוללת דף אחד, אפשר להשתמש NavigationRoute עד תשובה ספציפית לכל בקשות ניווט.

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);

בכל פעם שמשתמש נכנס לאתר שלכם דרך הדפדפן, הבקשה להצגת הדף תהיה בקשת ניווט, ותוצג הדף שנשמר במטמון /app-shell.html. (הערה: צריך לשמור את הדף במטמון דרך workbox-precaching או דרך בשלב ההתקנה עצמו).

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

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [new RegExp('/blog/')],
  denylist: [new RegExp('/blog/restricted/')],
});
registerRoute(navigationRoute);

חשוב רק לזכור שהשדה denylist ינצח אם כתובת URL מסוימת נמצאת בשני המקומות allowlist וdenylist.

הגדרת handler ברירת מחדל

אם רוצים לספק 'handler' לבקשות שלא תואמות למסלול, אתם יכול להגדיר handler ברירת מחדל.

import {setDefaultHandler} from 'workbox-routing';

setDefaultHandler(({url, event, params}) => {
  // ...
});

הגדרת מטפל תפיסה

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

import {setCatchHandler} from 'workbox-routing';

setCatchHandler(({url, event, params}) => {
  ...
});

הגדרת נתיב לבקשות שאינן מסוג GET

ההנחה היא שכל המסלולים הם עבור בקשות GET כברירת מחדל.

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

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb, 'POST');
registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');

רישום ביומן של נתב

אפשר לזהות את זרימת הבקשה בעזרת היומנים של workbox-routing, שידגיש אילו כתובות URL נמצאות בתהליך עיבוד דרך תיבת העבודה.

יומני ניתוב

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

ניפוי באגים והודעות ניתוב ביומן

שימוש מתקדם

אם אתם רוצים שתהיה לכם יותר שליטה על המועד שבו ניתן הנתב של תיבת העבודה תוכל ליצור בקשות משלך, מופע וקריאה של Router השעה handleRequest() method בכל פעם שרוצים להשתמש בנתב כדי להגיב לבקשה.

import {Router} from 'workbox-routing';

const router = new Router();

self.addEventListener('fetch', event => {
  const {request} = event;
  const responsePromise = router.handleRequest({
    event,
    request,
  });
  if (responsePromise) {
    // Router found a route to handle the request.
    event.respondWith(responsePromise);
  } else {
    // No route was found to handle the request.
  }
});

כשמשתמשים ישירות ב-Router, צריך להשתמש גם במחלקה Route, או כל אחת מהמחלקות המתרחבות כדי לרשום מסלולים.

import {Route, RegExpRoute, NavigationRoute, Router} from 'workbox-routing';

const router = new Router();
router.registerRoute(new Route(matchCb, handlerCb));
router.registerRoute(new RegExpRoute(new RegExp(...), handlerCb));
router.registerRoute(new NavigationRoute(handlerCb));

סוגים

NavigationRoute

ניווט במסלול מאפשר ליצור בקלות workbox-routing.Route שתואם לדפדפן [בקשות ניווט]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests.

הוא יתאים רק לבקשות נכנסות https://fetch.spec.whatwg.org/#concept-request-mode|mode מוגדר ל-navigate.

אפשר להחיל את המסלול הזה רק על קבוצת משנה של בקשות ניווט באמצעות אחד מהפרמטרים denylist ו-allowlist, או שניהם.

מאפיינים

  • constructor

    ריק

    אם תספקו גם את denylist וגם את allowlist, denylist יקבלו קדימות והבקשה לא תתאים למסלול הזה.

    הביטויים הרגולריים בallowlist ובdenylist תהיה התאמה מול המשורשרים [pathname]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname וגם [search]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search חלקים של כתובת האתר המבוקשת.

    הערה: המערכת עשויה להעריך את ביטויים רגולריים אלה ביחס לכל כתובת יעד במהלך ניווט. עדיף להימנע משימוש complex RegExps, אחרת, המשתמשים עשויים לראות עיכובים בזמן הניווט באתר.

    הפונקציה constructor נראית כך:

    (handler: RouteHandler, options?: NavigationRouteMatchOptions) => {...}

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    ריק

    הפונקציה setCatchHandler נראית כך:

    (handler: RouteHandler) => {...}

    • handler

      התקשרות חזרה פונקציה שמחזירה תגובה ל-Promise

NavigationRouteMatchOptions

מאפיינים

  • רשימת היתרים

    RegExp[] אופציונלי

  • רשימת ישויות שנחסמו

    RegExp[] אופציונלי

RegExpRoute

באמצעות RegExpRoute קל ליצור ביטוי רגולרי שמבוסס על workbox-routing.Route

בבקשות ממקור זהה, הפרמטר RegExp צריך להתאים רק לחלק מכתובת ה-URL. עבור בהתחלה של כתובת ה-URL.

מאפיינים

  • constructor

    ריק

    אם הביטוי הרגולרי מכיל [לכידת קבוצות]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references, הערכים שתועדו יועברו workbox-routing~handlerCallback params ארגומנט.

    הפונקציה constructor נראית כך:

    (regExp: RegExp, handler: RouteHandler, method?: HTTPMethod) => {...}

    • regExp

      RegExp

      הביטוי הרגולרי שצריך להתאים מול כתובות URL.

    • handler

      התקשרות חזרה מחזירה 'Promise' (הבטחה) שמובילה לתגובה.

    • method

      שיטת HTTP אופציונלית

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    ריק

    הפונקציה setCatchHandler נראית כך:

    (handler: RouteHandler) => {...}

    • handler

      התקשרות חזרה פונקציה שמחזירה תגובה ל-Promise

Route

Route מורכב מזוג פונקציות קריאה חוזרת – "match" ו-'handler'. "התאמה" קריאה חוזרת (callback) קובעת אם צריך להשתמש במסלול כדי "לטפל" A באמצעות החזרת ערך שאינו קביל, אם הוא יכול. ה-"handler" התקשרות חזרה נקרא כאשר יש התאמה והוא צריך להחזיר הבטחה שפותרת Response.

מאפיינים

  • constructor

    ריק

    בונה המחלקה במסלול.

    הפונקציה constructor נראית כך:

    (match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}

    • התאמה

      פונקציית קריאה חוזרת שקובעת אם המסלול תואם האירוע fetch שמוחזר לערך שאינו דמה.

    • handler

      התקשרות חזרה פונקציה שמחזירה תגובה ל-Promise.

    • method

      שיטת HTTP אופציונלית

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    ריק

    הפונקציה setCatchHandler נראית כך:

    (handler: RouteHandler) => {...}

    • handler

      התקשרות חזרה פונקציה שמחזירה תגובה ל-Promise

Router

אפשר להשתמש בנתב כדי לעבד FetchEvent באמצעות נתב אחד או יותר workbox-routing.Route, תגובה עם Response אם קיים מסלול תואם.

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

אם המסלול התואם יקפיץ שגיאה, הנתב ישתמש ב"תפיסה" (catch) את המטפל אם מוגדר לטפל בבעיות בצורה חלקה ולתת מענה בקשה.

אם הבקשה תואמת לכמה מסלולים, המסלול המוקדם ביותר שרשום במערכת ישמשו לתגובה לבקשה.

מאפיינים

  • constructor

    ריק

    הפעלת נתב חדש.

    הפונקציה constructor נראית כך:

    () => {...}

  • נתיבים

    Map&lt;HTTPMethodRoute[]&gt;

  • addCacheListener

    ריק

    הוספה של האזנה לאירועי הודעה לכתובות URL לשמירה במטמון מהחלון. התכונה הזו שימושית לשמירה במטמון של משאבים שנטענו בדף לפני התאריך שבו Service Worker התחיל לשלוט בו.

    הפורמט של נתוני ההודעה שנשלחים מהחלון אמור להיות בפורמט הבא. כאשר המערך urlsToCache יכול להכיל מחרוזות של כתובות URL או מערך של מחרוזת URL + אובייקט requestInit (כמו שמעבירים אל fetch()).

    {
      type: 'CACHE_URLS',
      payload: {
        urlsToCache: [
          './script1.js',
          './script2.js',
          ['./script3.js', {mode: 'no-cors'}],
        ],
      },
    }
    

    הפונקציה addCacheListener נראית כך:

    () => {...}

  • addFetchListener

    ריק

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

    הפונקציה addFetchListener נראית כך:

    () => {...}

  • findMatchingRoute

    ריק

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

    הפונקציה findMatchingRoute נראית כך:

    (options: RouteMatchCallbackOptions) => {...}

    • החזרות

      אובייקט

      אובייקט עם המאפיינים route ו-params. הם מאוכלסים אם נמצא מסלול תואם או undefined אחרת.

  • handleRequest

    ריק

    יש להחיל את כללי הניתוב על אובייקט FetchEvent כדי לקבל תשובה ה-handler של הנתיב המתאים.

    הפונקציה handleRequest נראית כך:

    (options: object) => {...}

    • אפשרויות

      אובייקט

      • אירוע

        ExtendableEvent

        האירוע שהפעיל בקשה.

      • בקשה

        בקשה

        הבקשה לטיפול.

    • החזרות

      Promise&lt;Response&gt;

      הבטחה מוחזרת אם המסלול הרשום יכול לטפל בבקשה. אם לא נמצאה התאמה המסלול ואין defaultHandler, מוחזר undefined.

  • registerRoute

    ריק

    רושם מסלול בנתב.

    הפונקציה registerRoute נראית כך:

    (route: Route) => {...}

  • setCatchHandler

    ריק

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

    הפונקציה setCatchHandler נראית כך:

    (handler: RouteHandler) => {...}

    • handler

      התקשרות חזרה פונקציה שמחזירה את Promise שמובילה לתשובה.

  • setDefaultHandler

    ריק

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

    כל method של HTTP ('GET', 'POST' וכו') מקבלת handler משלה שמוגדר כברירת מחדל.

    ללא handler שמוגדר כברירת מחדל, בקשות שלא מולאו יעברו אל כאילו אין קובץ שירות (service worker).

    הפונקציה setDefaultHandler נראית כך:

    (handler: RouteHandler, method?: HTTPMethod) => {...}

    • handler

      התקשרות חזרה פונקציה שמחזירה את Promise שמובילה לתשובה.

    • method

      שיטת HTTP אופציונלית

  • unregisterRoute

    ריק

    מבטל את הרישום של מסלול באמצעות הנתב.

    הפונקציה unregisterRoute נראית כך:

    (route: Route) => {...}

    • נתיב

      הנתיב לביטול הרישום.

שיטות

registerRoute()

workbox-routing.registerRoute(
  capture: string | RegExp | RouteMatchCallback | Route,
  handler?: RouteHandler,
  method?: HTTPMethod,
)

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

השיטה הזו תיצור עבורך נתיב במקרה הצורך, קוראים לפונקציה workbox-routing.Router#registerRoute.

פרמטרים

  • צילום

    string | RegExp | RouteMatchCallback | מסלול

    אם פרמטר הצילום הוא Route, המערכת תתעלם מכל שאר הארגומנטים.

  • handler

    RouteHandler אופציונלי

  • method

    שיטת HTTP אופציונלית

החזרות

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

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

פרמטרים

  • handler

    התקשרות חזרה מחזירה 'Promise' (הבטחה) שמובילה לתגובה.

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

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

ללא handler שמוגדר כברירת מחדל, בקשות שלא מולאו יעברו אל כאילו אין קובץ שירות (service worker).

פרמטרים

  • handler

    התקשרות חזרה פונקציה שמחזירה את Promise שמובילה לתשובה.