enrutamiento de caja de trabajo

Un service worker puede interceptar solicitudes de red de una página. Puede responder al navegador con contenido almacenado en caché, contenido de la red o contenido generado en el service worker.

workbox-routing es un módulo que facilita la “enrutamiento” de estas solicitudes a diferentes funciones que proporcionan respuestas.

Cómo se realiza el enrutamiento

Cuando una solicitud de red genera un evento de recuperación de un service worker, workbox-routing intentará responder a la solicitud con las rutas y los controladores proporcionados.

Diagrama de enrutamiento de cajas de trabajo

Los aspectos principales que debes tener en cuenta de lo anterior son los siguientes:

  • El método de una solicitud es importante. De forma predeterminada, las rutas se registran para las solicitudes GET. Si deseas interceptar otros tipos de solicitudes, deberás especificar el método.

  • El orden del registro de la ruta es importante. Si se registran varias rutas que pueden controlar una solicitud, la ruta que se registre primero se usará para responder a la solicitud.

Existen varias formas de registrar una ruta: puedes usar devoluciones de llamada, expresiones regulares o instancias de Route.

Coincidencia y manejo en las rutas

Una "ruta" en el cuadro de trabajo no tiene más de dos funciones: una de "coincidencia" para determinar si la ruta debe coincidir con una solicitud y una función de "manejo", que debe controlar la solicitud y responder con una respuesta.

Workbox incluye algunos asistentes que realizarán la coincidencia y el manejo por ti, pero si en algún momento deseas tener un comportamiento diferente, escribir una función de controlador y coincidencia personalizada es la mejor opción.

A una función de devolución de llamada de coincidencia se le pasa un ExtendableEvent, un Request y un objeto URL que puedes hacer para mostrar un valor de verdad. En un ejemplo sencillo, podrías hacer coincidir con una URL específica de esta manera:

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

La mayoría de los casos de uso se pueden abordar examinando o probando url o request.

Una función de devolución de llamada de controlador recibirá el mismo ExtendableEvent, Request y URL objeto junto con un valor params, que es el valor que muestra la función "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,
  });
};

Tu controlador debe mostrar una promesa que se resuelva en un Response. En este ejemplo, usamos async y await. De forma interna, el valor Response que se muestra se incluirá en una promesa.

Puedes registrar estas devoluciones de llamada de la siguiente manera:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

La única limitación es que la devolución de llamada "match" debe mostrar de forma síncrona un valor de verdad, no puedes realizar ningún trabajo asíncrono. El motivo es que Router debe responder de manera síncrona al evento de recuperación o permitir pasar a otros eventos de recuperación.

Por lo general, la devolución de llamada "handler" usa una de las estrategias proporcionadas por workbox-strategies de la siguiente manera:

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

registerRoute(matchCb, new StaleWhileRevalidate());

En esta página, nos enfocaremos en workbox-routing, pero puedes obtener más información acerca de estas estrategias en estrategias de cuadros de trabajo.

Cómo registrar una ruta de expresión regular

Una práctica común es usar una expresión regular en lugar de una devolución de llamada de "coincidencia". Workbox hace que esto sea fácil de implementar de la siguiente manera:

import {registerRoute} from 'workbox-routing';

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

Para solicitudes del mismo origen, esta expresión regular coincidirá siempre que la URL de la solicitud coincida con la expresión regular.

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

Sin embargo, para las solicitudes de origen cruzado, las expresiones regulares deben coincidir con el comienzo de la URL. El motivo es que no es probable que, con una expresión regular new RegExp('/styles/.*\\.css'), pretendas hacer coincidir archivos CSS de terceros.

  • 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

Si deseas este comportamiento, solo debes asegurarte de que la expresión regular coincida con el comienzo de la URL. Si quisiéramos hacer coincidir las solicitudes de https://cdn.third-party-site.com, podríamos usar la expresión regular 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

Si quieres hacer coincidir tanto locales como terceros, puedes usar un comodín al comienzo de tu expresión regular, pero debes hacerlo con precaución para garantizar que no cause comportamientos inesperados en tu app web.

Cómo registrar una ruta de navegación

Si tu sitio es una app de una sola página, puedes usar un NavigationRoute a fin de mostrar una respuesta específica para todas las solicitudes de navegación.

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);

Cada vez que un usuario visite tu sitio en el navegador, la solicitud de la página será una solicitud de navegación y se entregará la página almacenada en caché /app-shell.html. (Nota: Debes tener la página almacenada en caché a través de workbox-precaching o de tu propio paso de instalación).

De forma predeterminada, esto responderá a todas las solicitudes de navegación. Si deseas restringirla para que responda a un subconjunto de URLs, puedes usar las opciones allowlist y denylist a fin de restringir qué páginas coincidirán con esta ruta.

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);

Lo único que debes tener en cuenta es que denylist ganará si una URL se encuentra en allowlist y denylist.

Cómo configurar un controlador predeterminado

Si deseas suministrar un “controlador” para las solicitudes que no coinciden con una ruta, puedes configurar un controlador predeterminado.

import {setDefaultHandler} from 'workbox-routing';

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

Cómo configurar un controlador de captura

Si alguna de las rutas arroja un error, puedes capturar y disminuir el nivel de forma elegante mediante la configuración de un controlador de captura.

import {setCatchHandler} from 'workbox-routing';

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

Cómo definir una ruta para solicitudes que no son GET

De forma predeterminada, se supone que todas las rutas corresponden a solicitudes de GET.

Si deseas enrutar otras solicitudes, como una solicitud POST, debes definir el método cuando registres la ruta, de la siguiente manera:

import {registerRoute} from 'workbox-routing';

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

Registro del router

Deberías poder determinar el flujo de una solicitud con los registros de workbox-routing, que destacarán las URLs que se procesan a través de Workbox.

Enrutamiento de registros

Si necesitas información más detallada, puedes configurar el nivel de registro en debug para ver los registros de las solicitudes que no maneja el router. Consulta nuestra guía de depuración para obtener más información sobre cómo configurar el nivel de registro.

Mensajes de enrutamiento de registros y depuración

Uso avanzado

Si deseas tener más control sobre cuándo se envían solicitudes al router de la caja de trabajo, puedes crear tu propia instancia de Router y llamar al método handleRequest() cada vez que quieras usar el router para responder a una solicitud.

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.
  }
});

Cuando uses Router directamente, también deberás usar la clase Route o cualquiera de las clases extendidas para registrar rutas.

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));

Tipos

NavigationRoute

NavigationRoute facilita la creación de un workbox-routing.Route que coincide con el navegador [solicitudes de navegación]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests.

Solo coincidirá con las solicitudes entrantes cuyo https://fetch.spec.whatwg.org/#concept-request-mode|mode esté configurado como navigate.

Opcionalmente, solo puedes aplicar esta ruta a un subconjunto de solicitudes de navegación con uno de los parámetros denylist y allowlist, o ambos.

Propiedades

  • constructor

    void

    Si se proporcionan denylist y allowlist, denylist tendrá prioridad y la solicitud no coincidirá con esta ruta.

    Las expresiones regulares de allowlist y denylist se comparan con las partes concatenadas [pathname]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname y [search]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search de la URL solicitada.

    Nota: Estas expresiones regulares se pueden evaluar en comparación con todas las URL de destino durante una navegación. Evita usar Expresiones regulares complejas. De lo contrario, los usuarios podrían experimentar demoras cuando navegan por el sitio.

    La función constructor se ve de la siguiente manera:

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

  • catchHandler
  • controlador
  • coincidencia
  • method

    HTTPMethod

  • setCatchHandler

    void

    La función setCatchHandler se ve de la siguiente manera:

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

    • controlador

      Una función de devolución de llamada que muestra una promesa que resuelve una respuesta

NavigationRouteMatchOptions

Propiedades

  • lista de anunciantes permitidos

    RegExp[] opcional

  • lista de bloqueo

    RegExp[] opcional

RegExpRoute

RegExpRoute facilita la creación de una expresión regular basada workbox-routing.Route.

Para las solicitudes del mismo origen, la expresión regular solo debe coincidir con una parte de la URL. Para las solicitudes en servidores de terceros, debes definir un regex que coincida con el inicio de la URL.

Propiedades

  • constructor

    void

    Si la expresión regular contiene [capture groups]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references, los valores capturados se pasarán al argumento workbox-routing~handlerCallback params.

    La función constructor se ve de la siguiente manera:

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

    • regExp

      RegExp

      La expresión regular que debe coincidir con las URLs.

    • controlador

      Una función de devolución de llamada que muestra una promesa que genera una respuesta

    • method

      HTTPMethod opcional

  • catchHandler
  • controlador
  • coincidencia
  • method

    HTTPMethod

  • setCatchHandler

    void

    La función setCatchHandler se ve de la siguiente manera:

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

    • controlador

      Una función de devolución de llamada que muestra una promesa que resuelve una respuesta

Route

Un Route consta de un par de funciones de devolución de llamada: "match" y "handler". La devolución de llamada "match" determina si se debe usar una ruta para "controlar" una solicitud, ya que muestra un valor que no es falso si es posible. Se llama a la devolución de llamada de “controlador” cuando hay una coincidencia y esta debería mostrar una promesa que se resuelva en un Response.

Propiedades

  • constructor

    void

    Constructor de la clase Route.

    La función constructor se ve de la siguiente manera:

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

    • coincidencia

      Una función de devolución de llamada que determina si la ruta coincide con un evento fetch determinado mostrando un valor que no es falso

    • controlador

      Una función de devolución de llamada que muestra una promesa que resuelve una respuesta.

    • method

      HTTPMethod opcional

  • catchHandler
  • controlador
  • coincidencia
  • method

    HTTPMethod

  • setCatchHandler

    void

    La función setCatchHandler se ve de la siguiente manera:

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

    • controlador

      Una función de devolución de llamada que muestra una promesa que resuelve una respuesta

Router

El router se puede usar para procesar un FetchEvent con uno o más workbox-routing.Route, que responde con un Response si existe una ruta coincidente.

Si ninguna ruta coincide con una solicitud determinada, el router usará un controlador “predeterminado” si hay uno definido.

Si la ruta coincidente arroja un error, el router usará un controlador “catch” si uno está definido para abordar los problemas de forma más fluida y responder con una solicitud.

Si una solicitud coincide con varias rutas, se usará la ruta registrada más antigua para responder a la solicitud.

Propiedades

  • constructor

    void

    Inicializa un router nuevo.

    La función constructor se ve de la siguiente manera:

    ()=> {...}

  • rutas

    Map<HTTPMethodRoute[]>

  • addCacheListener

    void

    Agrega un objeto de escucha de eventos de mensaje para las URLs que se deben almacenar en caché desde la ventana. Esto es útil para almacenar en caché los recursos cargados en la página antes de que el service worker comenzó a controlarla.

    El formato de los datos del mensaje enviados desde la ventana debe ser el siguiente. En el ejemplo anterior, el array urlsToCache puede constar de cadenas de URL o un array de cadena de URL + objeto requestInit (lo mismo que pasarías a fetch()).

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

    La función addCacheListener se ve de la siguiente manera:

    ()=> {...}

  • addFetchListener

    void

    Agrega un objeto de escucha de eventos de recuperación para responder a los eventos cuando una ruta coincide con la solicitud del evento.

    La función addFetchListener se ve de la siguiente manera:

    ()=> {...}

  • findMatchingRoute

    void

    Verifica una solicitud y la URL (y, de forma opcional, un evento) con la lista de rutas registradas y, si hay una coincidencia, muestra la ruta correspondiente junto con los parámetros que genera la coincidencia.

    La función findMatchingRoute se ve de la siguiente manera:

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

    • resultados

      objeto

      Un objeto con propiedades route y params. Se propagan si se encuentra una ruta coincidente o, de lo contrario, undefined.

  • handleRequest

    void

    Aplica las reglas de enrutamiento a un objeto FetchEvent para obtener una respuesta de un controlador de Route adecuado.

    La función handleRequest se ve de la siguiente manera:

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

    • Opciones

      objeto

      • event

        ExtendableEvent

        El evento que activó la solicitud.

      • request

        Solicitud

        Es la solicitud que se debe controlar.

    • resultados

      Promesa<Respuesta>

      Se muestra una promesa si una ruta registrada puede controlar la solicitud. Si no hay una ruta que coincida ni un defaultHandler, se mostrará undefined.

  • registerRoute

    void

    Registra una ruta con el router.

    La función registerRoute se ve de la siguiente manera:

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

    • ruta

      La ruta que se registrará.

  • setCatchHandler

    void

    Si una ruta arroja un error mientras se maneja una solicitud, se llamará a este handler y se le dará la oportunidad de proporcionar una respuesta.

    La función setCatchHandler se ve de la siguiente manera:

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

    • controlador

      Una función de devolución de llamada que muestra una promesa que genera una respuesta

  • setDefaultHandler

    void

    Define un handler predeterminado al que se llame cuando no hay rutas que coincidan explícitamente con la solicitud entrante.

    Cada método HTTP (“GET”, “POST”, etc.) obtiene su propio controlador predeterminado.

    Sin un controlador predeterminado, las solicitudes sin coincidencias irán en la red como si no hubiera un service worker presente.

    La función setDefaultHandler se ve de la siguiente manera:

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

    • controlador

      Una función de devolución de llamada que muestra una promesa que genera una respuesta

    • method

      HTTPMethod opcional

  • unregisterRoute

    void

    Cancela el registro de una ruta con el router.

    La función unregisterRoute se ve de la siguiente manera:

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

    • ruta

      La ruta para cancelar el registro.

Métodos

registerRoute()

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

Registra con facilidad una expresión regular, cadena o función con una estrategia de almacenamiento en caché en una instancia de router singleton.

Si es necesario, este método generará una ruta y llamará a workbox-routing.Router#registerRoute.

Parámetros

  • capturar

    string|RegExp|RouteMatchCallback|Ruta

    Si el parámetro de captura es Route, se ignorarán todos los demás argumentos.

  • controlador

    RouteHandler opcional

  • method

    HTTPMethod opcional

Devuelve

  • El Route generado

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

Si una ruta arroja un error mientras se maneja una solicitud, se llamará a este handler y se le dará la oportunidad de proporcionar una respuesta.

Parámetros

  • controlador

    Una función de devolución de llamada que muestra una promesa que genera una respuesta

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

Define un handler predeterminado al que se llame cuando no hay rutas que coincidan explícitamente con la solicitud entrante.

Sin un controlador predeterminado, las solicitudes sin coincidencias irán en la red como si no hubiera un service worker presente.

Parámetros

  • controlador

    Una función de devolución de llamada que muestra una promesa que genera una respuesta