roteamento da caixa de trabalho

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.

Diagrama de roteamento da caixa de trabalho

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.

Registros de roteamento

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.

Depurar e registrar mensagens de roteamento

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

  • construtor

    void

    Se denylist e allowlist forem fornecidos, denylist terá precedência e a solicitação não corresponderá a essa rota.

    As expressões regulares em allowlist e denylist 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)=> {...}

  • catchHandler
  • gerenciador
  • correspondência
  • method

    HTTPMethod

  • setCatchHandler

    void

    A função setCatchHandler tem esta aparência:

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

    • gerenciador

      Função de callback que retorna uma promessa que é resolvida em uma resposta.

NavigationRouteMatchOptions

Propriedades

  • lista de permissões

    RegExp[] opcional

  • lista de bloqueio

    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 argumento workbox-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.

    • gerenciador

      Uma função de callback que retorna uma promessa, resultando em uma resposta.

    • method

      HTTPMethod opcional

  • catchHandler
  • gerenciador
  • correspondência
  • method

    HTTPMethod

  • setCatchHandler

    void

    A função setCatchHandler tem esta aparência:

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

    • gerenciador

      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.

    • gerenciador

      Uma função de callback que retorna uma promessa que é resolvida em uma resposta.

    • method

      HTTPMethod opcional

  • catchHandler
  • gerenciador
  • correspondência
  • method

    HTTPMethod

  • setCatchHandler

    void

    A função setCatchHandler tem esta aparência:

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

    • gerenciador

      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:

    ()=> {...}

  • 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 + objeto requestInit (a mesma forma que você transmitiria para fetch()).

    {
      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)=> {...}

    • retorna

      objeto

      Um objeto com as propriedades route e params. Elas serão preenchidas se uma rota correspondente for encontrada ou se undefined 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)=> {...}

    • opções

      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)=> {...}

    • gerenciador

      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)=> {...}

    • gerenciador

      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.

  • gerenciador

    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

  • gerenciador

    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

  • gerenciador

    Uma função de callback que retorna uma promessa, resultando em uma resposta.