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.
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 sí 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.
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.
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
-
void
Si se proporcionan
denylist
yallowlist
,denylist
tendrá prioridad y la solicitud no coincidirá con esta ruta.Las expresiones regulares de
allowlist
ydenylist
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) => {...}
-
Una función de devolución de llamada que muestra una promesa que genera una respuesta
-
NavigationRouteMatchOptions opcional
-
-
RouteHandlerObject opcional
-
HTTPMethod
-
void
La función
setCatchHandler
se ve de la siguiente manera:(handler: RouteHandler) => {...}
-
Una función de devolución de llamada que muestra una promesa que resuelve una respuesta
-
NavigationRouteMatchOptions
Propiedades
-
RegExp[] opcional
-
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 argumentoworkbox-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
-
resultados
-
-
catchHandler
RouteHandlerObject opcional
-
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
-
resultados
-
-
catchHandler
RouteHandlerObject opcional
-
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:() => {...}
-
resultados
-
-
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 + objetorequestInit
(lo mismo que pasarías afetch()
).{ 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) => {...}
-
Opciones
-
resultados
objeto
Un objeto con propiedades
route
yparams
. 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 | Route
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