Um service worker pode interceptar solicitações de rede para uma página. Ele pode responder ao navegador com conteúdo armazenado em cache, conteúdo da rede ou conteúdo gerado no service worker.
O workbox-routing
é um módulo que facilita o "encaminhar" dessas solicitações para
diferentes funções que fornecem respostas.
Como é feito o roteamento
Quando uma solicitação de rede causa um evento de busca de service worker, o workbox-routing
tenta responder à solicitação usando as rotas e gerenciadores fornecidos.
As principais coisas a observar acima são:
O método de uma solicitação é importante. Por padrão, as rotas são registradas para solicitações
GET
. Se você quiser interceptar outros tipos de solicitações, será necessário especificar o método.A ordem do registro de rota é importante. Se houver várias rotas registradas que possam processar uma solicitação, aquela que estiver registrada primeiro será usada para responder à solicitação.
Existem algumas maneiras de registrar uma rota: use callbacks, expressões regulares ou instâncias de rota.
Correspondência e manipulação em rotas
Uma "rota" na caixa de trabalho é nada mais que duas funções: uma função "correspondente" para determinar se a rota precisa corresponder a uma solicitação e uma função de "processamento", que deve processar a solicitação e responder com uma resposta.
O Workbox vem com alguns auxiliares que realizam a correspondência e o processamento para você, mas se você quiser um comportamento diferente, criar uma função de correspondência e de gerenciador personalizada é a melhor opção.
Uma
função de callback de correspondência
recebe um
ExtendableEvent
,
Request
e um
objeto URL
que pode ser correspondente
retornando um valor verdadeiro. Por um exemplo simples, você pode fazer a correspondência com um URL específico, como:
const matchCb = ({url, request, event}) => {
return url.pathname === '/special/url';
};
A maioria dos casos de uso pode ser abordada com a análise / teste de url
ou
request
.
Uma
função de callback do gerenciador
recebe os mesmos
ExtendableEvent
,
Request
e
objeto URL
com
um valor params
, que é o valor retornado pela função "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,
});
};
Seu gerenciador precisa retornar uma promessa que se resolve como um Response
. Neste
exemplo, usamos
async
e await
.
Internamente, o valor Response
retornado será encapsulado em uma promessa.
Você pode registrar esses callbacks da seguinte maneira:
import {registerRoute} from 'workbox-routing';
registerRoute(matchCb, handlerCb);
A única limitação é que o callback "match" precisa retornar um valor de verdade
de maneira síncrona. Não é possível realizar trabalhos assíncronos. O motivo é que
Router
precisa responder de maneira síncrona ao evento de busca ou permitir a passagem
para outros eventos de busca.
Normalmente, o callback "gerenciador" usaria uma das estratégias fornecidas por estratégias de caixa de trabalho da seguinte maneira:
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
registerRoute(matchCb, new StaleWhileRevalidate());
Nesta página, vamos nos concentrar em workbox-routing
, mas você pode
saber mais sobre essas estratégias em estratégias de caixa de trabalho.
Como registrar uma rota de expressão regular
Uma prática comum é usar uma expressão regular em vez de um callback de "correspondência". O Workbox facilita a implementação desse recurso da seguinte forma:
import {registerRoute} from 'workbox-routing';
registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);
Para solicitações da mesma origem, essa expressão regular vai corresponder, desde que o URL da solicitação corresponda à expressão regular.
- https://example.com/styles/main.css
- https://example.com/styles/nested/file.css
- https://example.com/nested/styles/directory.css
No entanto, para solicitações de origem cruzada, as expressões regulares precisam corresponder ao início do URL. O motivo é que,
com uma expressão regular new RegExp('/styles/.*\\.css')
,
é improvável que você quisesse corresponder arquivos CSS de terceiros.
- 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
Se você quis fazer esse comportamento, basta garantir que a expressão regular corresponda ao início do URL. Se quiséssemos corresponder às
solicitações de https://cdn.third-party-site.com
, poderíamos usar a expressão
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
Para corresponder ambos, é possível usar um caractere curinga no início da expressão regular. Porém, isso precisa ser feito com cuidado para garantir que não cause comportamentos inesperados no seu app da Web.
Como registrar uma rota de navegação
Caso seu site seja um app de página única, você pode usar um
NavigationRoute
para
retornar uma resposta específica para todas as
solicitações de navegação.
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);
Sempre que um usuário acessar seu site pelo navegador, a solicitação da página será uma de navegação, e a página /app-shell.html
armazenada em cache será exibida.
Observação: é preciso armazenar a página em cache por meio de workbox-precaching
ou por sua
própria etapa de instalação.
Por padrão, isso vai responder a todas as solicitações de navegação. Se você quiser restringi-la para responder a um subconjunto de URLs, use as opções allowlist
e denylist
para restringir quais páginas corresponderão a essa rota.
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);
A única coisa a notar é que denylist
vencerá se um URL estiver no
allowlist
e no denylist
.
Definir um gerenciador padrão
Se você quiser fornecer um "gerenciador" para solicitações que não correspondem a uma rota, defina um gerenciador padrão.
import {setDefaultHandler} from 'workbox-routing';
setDefaultHandler(({url, event, params}) => {
// ...
});
Definir um gerenciador de captura
Caso alguma das rotas gere um erro, é possível capturar e degradar suavemente definindo um gerenciador de captura.
import {setCatchHandler} from 'workbox-routing';
setCatchHandler(({url, event, params}) => {
...
});
Como definir uma rota para solicitações que não são GET
Por padrão, todas as rotas são consideradas para solicitações GET
.
Para rotear outras solicitações, como POST
, defina o método ao registrar a rota, desta forma:
import {registerRoute} from 'workbox-routing';
registerRoute(matchCb, handlerCb, 'POST');
registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');
Geração de registros de roteador
É possível determinar o fluxo de uma solicitação usando os registros de
workbox-routing
, que vão destacar quais URLs estão sendo processados
pelo Workbox.
Se você precisar de informações mais detalhadas, defina o nível de registro como debug
para
ver registros de solicitações não processadas pelo roteador. Consulte nosso guia de depuração para mais informações sobre como definir o nível de registro.
Uso avançado
Se quiser ter mais controle sobre quando o roteador do Workbox recebe
solicitações, crie sua própria instância
Router
e chame
o método handleRequest()
sempre que quiser usar o roteador para responder a uma solicitação.
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.
}
});
Ao usar o Router
diretamente, você também precisará usar a classe Route
ou qualquer uma das classes de extensão para registrar rotas.
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
O NavigationRoute facilita a criação de um
workbox-routing.Route
que corresponda às [solicitações de navegação]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests
do navegador.
Ela só corresponderá a solicitações recebidas com
https://fetch.spec.whatwg.org/#concept-request-mode|mode
definido como navigate
.
Como opção, só é possível aplicar essa rota a um subconjunto de solicitações de navegação
usando um ou ambos os parâmetros denylist
e allowlist
.
Propriedades
-
void
Se
denylist
eallowlist
forem fornecidos,denylist
terá precedência e a solicitação não corresponderá a essa rota.As expressões regulares em
allowlist
edenylist
são correspondidas com as partes concatenadas [pathname
]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname
e [search
]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search
do URL solicitado.Observação: essas RegExps podem ser avaliadas em relação a cada URL de destino durante uma navegação. Evite usar RegExps complexos, ou os usuários poderão ter atrasos ao navegar no site.
A função
constructor
tem esta aparência:(handler: RouteHandler, options?: NavigationRouteMatchOptions) => {...}
-
Uma função de callback que retorna uma promessa, resultando em uma resposta.
-
NavigationRouteMatchOptions opcional
-
-
RouteHandlerObject opcional
-
HTTPMethod
-
void
A função
setCatchHandler
tem esta aparência:(handler: RouteHandler) => {...}
-
Função de callback que retorna uma promessa que é resolvida em uma resposta.
-
NavigationRouteMatchOptions
Propriedades
-
RegExp[] opcional
-
RegExp[] opcional
RegExpRoute
RegExpRoute facilita a criação de uma expressão regular baseada em
workbox-routing.Route
.
Para solicitações de mesma origem, a expressão regular só precisa corresponder a parte do URL. Para solicitações relacionadas a servidores de terceiros, defina uma expressão regular que corresponda ao início do URL.
Propriedades
-
construtor
void
Se a expressão regular contiver [capture groups]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references
, os valores capturados serão transmitidos para o argumentoworkbox-routing~handlerCallback
params
.A função
constructor
tem esta aparência:(regExp: RegExp, handler: RouteHandler, method?: HTTPMethod) => {...}
-
regExp
RegExp
A expressão regular para corresponder aos URLs.
-
handler
Uma função de callback que retorna uma promessa, resultando em uma resposta.
-
method
HTTPMethod opcional
-
retorna
-
-
catchHandler
RouteHandlerObject opcional
-
handler
-
correspondência
-
method
HTTPMethod
-
setCatchHandler
void
A função
setCatchHandler
tem esta aparência:(handler: RouteHandler) => {...}
-
handler
Função de callback que retorna uma promessa que é resolvida em uma resposta.
-
Route
Um Route
consiste em um par de funções de callback: "match" e "handler".
O callback "match" determina se uma rota precisa ser usada para "processar" uma
solicitação, retornando um valor não false, se possível. O callback "handler" é chamado quando há uma correspondência e precisa retornar uma promessa que é resolvida com um Response
.
Propriedades
-
construtor
void
Construtor da classe Route.
A função
constructor
tem esta aparência:(match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}
-
correspondência
Uma função de callback que determina se a rota corresponde a um determinado evento
fetch
, retornando um valor não false. -
handler
Uma função de callback que retorna uma promessa que é resolvida em uma resposta.
-
method
HTTPMethod opcional
-
retorna
-
-
catchHandler
RouteHandlerObject opcional
-
handler
-
correspondência
-
method
HTTPMethod
-
setCatchHandler
void
A função
setCatchHandler
tem esta aparência:(handler: RouteHandler) => {...}
-
handler
Função de callback que retorna uma promessa que é resolvida em uma resposta.
-
Router
O roteador pode ser usado para processar um FetchEvent
usando um ou mais
workbox-routing.Route
, respondendo com um Response
se
existir uma rota correspondente.
Se nenhuma rota corresponder a uma determinada solicitação, o roteador usará um gerenciador "padrão", se houver um definido.
Se a rota correspondente gerar um erro, o roteador usará um gerenciador "catch" se um estiver definido para lidar corretamente com problemas e responder com uma solicitação.
Se uma solicitação corresponder a vários trajetos, a rota registrada mais antiga será usada para responder a ela.
Propriedades
-
construtor
void
Inicializa um novo roteador.
A função
constructor
tem esta aparência:() => {...}
-
retorna
-
-
rotas
Map<HTTPMethodRoute[]>
-
addCacheListener
void
Adiciona um listener de eventos de mensagem para que os URLs sejam armazenados em cache da janela. Isso é útil para armazenar em cache os recursos carregados na página antes de o service worker começar a controlá-los.
O formato dos dados da mensagem enviados pela janela deve ser o seguinte. Em que a matriz
urlsToCache
pode consistir em strings de URL ou uma matriz de string de URL + objetorequestInit
(a mesma forma que você transmitiria parafetch()
).{ type: 'CACHE_URLS', payload: { urlsToCache: [ './script1.js', './script2.js', ['./script3.js', {mode: 'no-cors'}], ], }, }
A função
addCacheListener
tem esta aparência:() => {...}
-
addFetchListener
void
Adiciona um listener de eventos de busca para responder a eventos quando uma rota corresponde à solicitação do evento.
A função
addFetchListener
tem esta aparência:() => {...}
-
findMatchingRoute
void
Verifica uma solicitação e um URL (e, opcionalmente, um evento) na lista de rotas registradas e, se houver uma correspondência, retorna a rota correspondente com todos os parâmetros gerados pela correspondência.
A função
findMatchingRoute
tem esta aparência:(options: RouteMatchCallbackOptions) => {...}
-
do modelo.
-
retorna
objeto
Um objeto com as propriedades
route
eparams
. Elas serão preenchidas se uma rota correspondente for encontrada ou seundefined
caso contrário.
-
-
handleRequest
void
Aplique as regras de roteamento a um objeto FetchEvent para receber uma resposta do gerenciador de um trajeto apropriado.
A função
handleRequest
tem esta aparência:(options: object) => {...}
-
do modelo.
objeto
-
event
ExtendableEvent
Evento que acionou a solicitação.
-
request
Solicitação
A solicitação a ser processada.
-
-
retorna
Promessa<Resposta>
Uma promessa vai ser retornada se uma rota registrada puder processar a solicitação. Se não houver nenhuma rota correspondente e se não houver
defaultHandler
,undefined
será retornado.
-
-
registerRoute
void
Registra uma rota com o roteador.
A função
registerRoute
tem esta aparência:(route: Route) => {...}
-
trajeto
A rota a ser registrada.
-
-
setCatchHandler
void
Se uma rota gerar um erro ao processar uma solicitação, esse
handler
será chamado e terá a chance de fornecer uma resposta.A função
setCatchHandler
tem esta aparência:(handler: RouteHandler) => {...}
-
handler
Uma função de callback que retorna uma promessa, resultando em uma resposta.
-
-
setDefaultHandler
void
Defina um
handler
padrão que seja chamado quando nenhuma rota corresponder explicitamente à solicitação recebida.Cada método HTTP ("GET", "POST" etc.) tem o próprio gerenciador padrão.
Sem um gerenciador padrão, as solicitações sem correspondência irão para a rede como se não houvesse um service worker presente.
A função
setDefaultHandler
tem esta aparência:(handler: RouteHandler, method?: HTTPMethod) => {...}
-
handler
Uma função de callback que retorna uma promessa, resultando em uma resposta.
-
method
HTTPMethod opcional
-
-
unregisterRoute
void
Cancela o registro de uma rota com o roteador.
A função
unregisterRoute
tem esta aparência:(route: Route) => {...}
-
trajeto
A rota para cancelar o registro.
-
Métodos
registerRoute()
workbox-routing.registerRoute(
capture: string | RegExp | RouteMatchCallback | Route,
handler?: RouteHandler,
method?: HTTPMethod,
)
Registre facilmente uma RegExp, string ou função com uma estratégia de armazenamento em cache para uma instância singleton do Router.
Esse método gerará uma rota para você, se necessário, e chamará workbox-routing.Router#registerRoute
.
Parâmetros
-
captura
string | RegExp | RouteMatchCallback | Rota
Se o parâmetro de captura for
Route
, todos os outros argumentos serão ignorados. -
handler
RouteHandler opcional
-
method
HTTPMethod opcional
Retorna
-
O
Route
gerado.
setCatchHandler()
workbox-routing.setCatchHandler(
handler: RouteHandler,
)
Se uma rota gerar um erro ao processar uma solicitação, esse handler
será chamado e terá a chance de fornecer uma resposta.
Parâmetros
-
handler
Uma função de callback que retorna uma promessa, resultando em uma resposta.
setDefaultHandler()
workbox-routing.setDefaultHandler(
handler: RouteHandler,
)
Defina um handler
padrão que seja chamado quando nenhuma rota corresponder explicitamente à solicitação recebida.
Sem um gerenciador padrão, as solicitações sem correspondência irão para a rede como se não houvesse um service worker presente.
Parâmetros
-
handler
Uma função de callback que retorna uma promessa, resultando em uma resposta.