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

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

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

כיצד מתבצע הניתוב

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

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

הנקודות העיקריות שיש לציין למעלה הם:

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

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

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

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

ל-"route" בתיבת העבודה יש לא יותר משתי פונקציות: פונקציה "matching" (התאמה) שקובעת אם המסלול צריך להתאים לבקשה, ופונקציית "handling" (טיפול), שאמורה לטפל בבקשה ולהגיב בתגובה.

ב-Workbox יש כמה כלי עזר שיאפשרו לכם לבצע את ההתאמה והטיפול, אבל אם אי פעם תרצו התנהגות אחרת, האפשרות הטובה ביותר היא לכתוב התאמה מותאמת אישית ופונקציה של 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 יהיה מוקף בהבטחה.

אפשר לרשום את הקריאות החוזרות (callback) כך:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

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

בדרך כלל, הקריאה החוזרת (callback) של "handler" תשתמש באחת מהאסטרטגיות שמספק אסטרטגיות ארגז העבודה, כגון:

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

registerRoute(matchCb, new StaleWhileRevalidate());

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

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

שיטה נפוצה היא להשתמש בביטוי רגולרי במקום בקריאה חוזרת (callback) של "התאמה". עם 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 ברירת מחדל.

import {setDefaultHandler} from 'workbox-routing';

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

הגדרה של אפליקציית תופסת

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

import {setCatchHandler} from 'workbox-routing';

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

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

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

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

import {registerRoute} from 'workbox-routing';

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

רישום נתב

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

יומני ניתוב

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

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

שימוש מתקדם

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

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

בעזרת 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

    void

    אם גם 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 של כתובת ה-URL המבוקשת.

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

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.

    • אפשרויות

      NavigationRouteMatchOptions אופציונלי

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    void

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה לתגובה

NavigationRouteMatchOptions

תכונות

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

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

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

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

RegExpRoute

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

בבקשות מאותו מקור, RegExp צריך להתאים רק לחלק מכתובת ה-URL. בבקשות שנשלחות נגד שרתים של צד שלישי, צריך להגדיר ביטוי רגולרי (regex) שתואם לתחילת כתובת ה-URL.

תכונות

  • Constructor

    void

    אם הביטוי הרגולרי מכיל [capture groups]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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.

    • method

      HTTPMethod אופציונלי

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    void

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה לתגובה

Route

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

תכונות

  • Constructor

    void

    בנאי של מחלקה מסוג 'מסלול'.

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

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

    • התאמה

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה לתשובה.

    • method

      HTTPMethod אופציונלי

  • catchHandler

    RouteHandlerObject אופציונלי

  • התאמה
  • method

    HTTPMethod

  • setCatchHandler

    void

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה לתגובה

Router

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

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

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

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

תכונות

  • Constructor

    void

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

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

    ()=> {...}

  • נתיבים

    Map<HTTPMethodRoute[]>

  • addCacheListener

    void

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

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

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

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

    ()=> {...}

  • addFetchListener

    void

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

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

    ()=> {...}

  • findMatchingRoute

    void

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

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

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

    • החזרות

      אובייקט

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

  • handleRequest

    void

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

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

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

    • אפשרויות

      אובייקט

      • אירוע

        ExtendableEvent

        האירוע שהקפיץ את הבקשה.

      • בקשה

        בקשה

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

    • החזרות

      הבטחה<Response>

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

  • registerRoute

    void

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

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

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

  • setCatchHandler

    void

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

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.

  • setDefaultHandler

    void

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

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

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

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

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

    • handler

      פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.

    • method

      HTTPMethod אופציונלי

  • unregisterRoute

    void

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

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

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

    • נתיב

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

שיטות

registerRoute()

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

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

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

פרמטרים

  • צילום

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

  • handler

    RouteHandler אופציונלי

  • method

    HTTPMethod אופציונלי

החזרות

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

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

פרמטרים

  • handler

    פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

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

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

פרמטרים

  • handler

    פונקציית קריאה חוזרת (callback) שמחזירה הבטחה, והתוצאה היא תשובה.