маршрутизация рабочего ящика

Работник службы может перехватывать сетевые запросы к странице. Он может отвечать браузеру кэшированным контентом, контентом из сети или контентом, созданным в сервис-воркере.

workbox-routing — это модуль, который позволяет легко «направлять» эти запросы к различным функциям, которые предоставляют ответы.

Как осуществляется маршрутизация

Когда сетевой запрос вызывает событие выборки сервисного работника, workbox-routing попытается ответить на запрос, используя предоставленные маршруты и обработчики.

Схема маршрутизации рабочей области

Основные моменты, на которые следует обратить внимание из вышеизложенного:

  • Важен метод запроса. По умолчанию маршруты регистрируются для запросов GET . Если вы хотите перехватывать другие типы запросов, вам необходимо указать метод.

  • Порядок регистрации Маршрута важен. Если зарегистрировано несколько маршрутов, которые могут обрабатывать запрос, для ответа на запрос будет использоваться тот маршрут, который зарегистрирован первым.

Есть несколько способов зарегистрировать маршрут: вы можете использовать обратные вызовы, регулярные выражения или экземпляры Route.

Сопоставление и обработка маршрутов

«Маршрут» в рабочей области — это не что иное, как две функции: функция «сопоставления», определяющая, должен ли маршрут соответствовать запросу, и функция «обработки», которая должна обрабатывать запрос и отвечать ответом.

Workbox поставляется с некоторыми помощниками, которые будут выполнять сопоставление и обработку за вас, но если вам когда-нибудь понадобится другое поведение, лучшим вариантом будет написание собственной функции сопоставления и обработчика.

В функцию обратного вызова match передаются ExtendableEvent , Request и объект URL , который вы можете сопоставить, вернув истинное значение. В качестве простого примера вы можете сопоставить определенный URL-адрес следующим образом:

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

Большинство случаев использования можно охватить путем изучения/тестирования либо url , либо request .

Функции обратного вызова обработчика будут переданы те же объекты 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,
  });
};

Ваш обработчик должен вернуть обещание, которое разрешается в Response . В этом примере мы используем async и await . Под капотом возвращаемое значение Response будет заключено в обещание.

Вы можете зарегистрировать эти обратные вызовы следующим образом:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

Единственное ограничение заключается в том, что обратный вызов «match» должен синхронно возвращать истинное значение, вы не можете выполнять какую-либо асинхронную работу. Причина этого в том, что Router должен синхронно реагировать на событие выборки или разрешать переход к другим событиям выборки.

Обычно обратный вызов «обработчика» использует одну из стратегий, предоставляемых стратегиями рабочего ящика, например:

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

registerRoute(matchCb, new StaleWhileRevalidate());

На этой странице мы сосредоточимся на workbox-routing , но вы можете узнать больше об этих стратегиях на странице Workbox-strategies .

Как зарегистрировать маршрут регулярного выражения

Обычной практикой является использование регулярного выражения вместо обратного вызова «соответствие». 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 //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 .

Установить обработчик по умолчанию

Если вы хотите предоставить «обработчик» для запросов, которые не соответствуют маршруту, вы можете установить обработчик по умолчанию.

import {setDefaultHandler} from 'workbox-routing';

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

Установите обработчик захвата

В случае, если какой-либо из ваших маршрутов выдает ошибку, вы можете корректно захватить и ухудшить ситуацию, установив обработчик catch.

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-адреса обрабатываются через 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 Performance-loading#first_what_are_navigation_requests .

Он будет соответствовать только входящим запросам, для которых https://fetch.spec.whatwg.org/#concept-request-mode|mode настроен на navigate .

При желании вы можете применить этот маршрут только к подмножеству запросов навигации, используя один или оба параметра списка denylist и allowlist .

Характеристики

  • конструктор

    пустота

    Если указаны и 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-адреса.

    Примечание . Эти регулярные выражения можно оценивать по каждому целевому URL-адресу во время навигации. Избегайте использования сложных регулярных выражений , иначе ваши пользователи могут столкнуться с задержками при навигации по вашему сайту.

    Функция constructor выглядит так:

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

  • catchHandler

    RouteHandlerObject необязательно

  • обработчик
  • соответствовать
  • метод

    HTTPМетод

  • УстановитьCatchHandler

    пустота

    Функция setCatchHandler выглядит так:

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

    • Функция обратного вызова, которая возвращает обещание, преобразующееся в ответ.

NavigationRouteMatchOptions

Характеристики

  • белый список

    RegExp[] необязательно

  • список запрещенных

    RegExp[] необязательно

RegExpRoute

RegExpRoute упрощает создание workbox-routing.Route на основе регулярных выражений.

Для запросов одного и того же происхождения RegExp должен соответствовать только части URL-адреса. Для запросов к сторонним серверам необходимо определить RegExp, соответствующий началу URL-адреса.

Характеристики

  • конструктор

    пустота

    Если регулярное выражение содержит [группы захвата] 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) => {...}

    • регулярное выражение

      Регэксп

      Регулярное выражение для сопоставления URL-адресов.

    • Функция обратного вызова, которая возвращает обещание, приводящее к ответу.

    • метод

      HTTPMethod необязательно

  • catchHandler

    RouteHandlerObject необязательно

  • обработчик
  • соответствовать
  • метод

    HTTPМетод

  • УстановитьCatchHandler

    пустота

    Функция setCatchHandler выглядит так:

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

    • Функция обратного вызова, которая возвращает обещание, преобразующееся в ответ.

Route

Route состоит из пары функций обратного вызова: «match» и «handler». Обратный вызов «match» определяет, следует ли использовать маршрут для «обработки» запроса, возвращая неложное значение, если это возможно. Обратный вызов «обработчика» вызывается при обнаружении совпадения и должен возвращать Promise, который преобразуется в Response .

Характеристики

  • конструктор

    пустота

    Конструктор класса Route.

    Функция constructor выглядит так:

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

    • соответствовать

      Функция обратного вызова, которая определяет, соответствует ли маршрут данному событию fetch , возвращая неложное значение.

    • Функция обратного вызова, которая возвращает обещание, преобразующееся в ответ.

    • метод

      HTTPMethod необязательно

  • catchHandler

    RouteHandlerObject необязательно

  • обработчик
  • соответствовать
  • метод

    HTTPМетод

  • УстановитьCatchHandler

    пустота

    Функция setCatchHandler выглядит так:

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

    • Функция обратного вызова, которая возвращает обещание, преобразующееся в ответ.

Router

Маршрутизатор можно использовать для обработки FetchEvent с использованием одного или нескольких workbox-routing.Route , отвечая Response , если соответствующий маршрут существует.

Если ни один маршрут не соответствует данному запросу, Маршрутизатор будет использовать обработчик «по умолчанию», если он определен.

Если соответствующий Маршрут выдает ошибку, Маршрутизатор будет использовать обработчик «catch», если он определен для корректного решения проблем и ответа Запросом.

Если запрос соответствует нескольким маршрутам, для ответа на запрос будет использоваться самый ранний зарегистрированный маршрут.

Характеристики

  • конструктор

    пустота

    Инициализирует новый маршрутизатор.

    Функция constructor выглядит так:

    () => {...}

  • маршруты

    Карта<HTTPMethodRoute[]>

  • добавитьCacheListener

    пустота

    Добавляет прослушиватель событий сообщений для кэширования URL-адресов из окна. Это полезно для кэширования ресурсов, загруженных на страницу, до того, как сервис-воркер начал ею управлять.

    Формат данных сообщения, отправляемого из окна, должен быть следующим. Где массив urlsToCache может состоять из строк URL-адресов или массива строк URL-адресов + объекта requestInit (так же, как вы передаете в fetch() ).

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

    Функция addCacheListener выглядит так:

    () => {...}

  • добавитьFetchListener

    пустота

    Добавляет прослушиватель событий выборки для реагирования на события, когда маршрут соответствует запросу события.

    Функция addFetchListener выглядит так:

    () => {...}

  • findMatchingRoute

    пустота

    Сверяет запрос и URL-адрес (и, при необходимости, событие) по списку зарегистрированных маршрутов и, если есть совпадение, возвращает соответствующий маршрут вместе со всеми параметрами, сгенерированными в результате совпадения.

    Функция findMatchingRoute выглядит так:

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

    • возвращает

      объект

      Объект со свойствами route и params . Они заполняются, если найден соответствующий маршрут, или в противном случае undefined .

  • handleRequest

    пустота

    Примените правила маршрутизации к объекту FetchEvent, чтобы получить ответ от соответствующего обработчика маршрута.

    Функция handleRequest выглядит так:

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

    • параметры

      объект

      • событие

        РасширяемоеСобытие

        Событие, вызвавшее запрос.

      • запрос

        Запрос

        Запрос на обработку.

    • возвращает

      Обещание<Ответ>

      Промис возвращается, если зарегистрированный маршрут может обработать запрос. Если соответствующего маршрута нет и нет defaultHandler , возвращается undefined .

  • РегистрацияМаршрут

    пустота

    Регистрирует маршрут на маршрутизаторе.

    Функция registerRoute выглядит так:

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

    • маршрут

      Маршрут регистрации.

  • УстановитьCatchHandler

    пустота

    Если Route выдает ошибку при обработке запроса, этот handler будет вызван и получит возможность предоставить ответ.

    Функция setCatchHandler выглядит так:

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

    • Функция обратного вызова, которая возвращает обещание, приводящее к ответу.

  • setDefaultHandler

    пустота

    Определите handler по умолчанию, который вызывается, когда ни один маршрут явно не соответствует входящему запросу.

    Каждый метод HTTP («GET», «POST» и т. д.) получает свой собственный обработчик по умолчанию.

    Без обработчика по умолчанию несовпадающие запросы будут отправляться в сеть, как если бы там не было сервисного работника.

    Функция setDefaultHandler выглядит так:

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

    • Функция обратного вызова, которая возвращает обещание, приводящее к ответу.

    • метод

      HTTPMethod необязательно

  • отменить регистрациюМаршрут

    пустота

    Отменяет регистрацию маршрута на маршрутизаторе.

    Функция unregisterRoute выглядит так:

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

    • маршрут

      Маршрут для отмены регистрации.

Методы

registerRoute()

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

Легко зарегистрировать RegExp, строку или функцию с помощью стратегии кэширования в одноэлементном экземпляре Router.

Этот метод при необходимости сгенерирует для вас маршрут и вызовет workbox-routing.Router#registerRoute .

Параметры

Возврат

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

Если Route выдает ошибку при обработке запроса, этот handler будет вызван и получит возможность предоставить ответ.

Параметры

  • Функция обратного вызова, которая возвращает обещание, приводящее к ответу.

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

Определите handler по умолчанию, который вызывается, когда ни один маршрут явно не соответствует входящему запросу.

Без обработчика по умолчанию несовпадающие запросы будут отправляться в сеть, как если бы там не было сервисного работника.

Параметры

  • Функция обратного вызова, которая возвращает обещание, приводящее к ответу.