Como configurar o comportamento de armazenamento em cache HTTP

Este codelab mostra como mudar os cabeçalhos de armazenamento em cache HTTP retornados por um servidor da Web baseado em Node.js, executando o framework de serviço Express. Ele também vai mostrar como confirmar se o comportamento de armazenamento em cache esperado está sendo aplicado usando o painel "Network" no Chrome DevTools.

Conhecer o projeto de exemplo

Estes são os principais arquivos com que você vai trabalhar no projeto de exemplo:

  • server.js contém o código Node.js que exibe o conteúdo do app da Web. Ele usa o Express para processar solicitações e respostas HTTP. Mais especificamente, express.static() é usado para disponibilizar todos os arquivos locais no diretório público. Portanto, a documentação do serve-static será útil.
  • public/index.html é o HTML do app da Web. Como a maioria dos arquivos HTML, ele não contém informações de controle de versão como parte do URL.
  • public/app.15261a07.js e public/style.391484cf.css são os recursos JavaScript e CSS do app da Web. Cada um desses arquivos contém um hash nos URLs, correspondente ao conteúdo. O index.html é responsável por manter o controle de qual URL com versão específica será carregado.

Configurar cabeçalhos de cache para o HTML

Ao responder a solicitações de URLs que não contêm informações de versão, adicione Cache-Control: no-cache às mensagens de resposta. Além disso, é recomendável definir um dos dois cabeçalhos de resposta adicionais: Last-Modified ou ETag. O index.html se enquadra nessa categoria. Você pode dividir isso em duas etapas.

Primeiro, os cabeçalhos Last-Modified e ETag são controlados pelas opções de configuração etag e lastModified. Na verdade, essas duas opções são padrão para true em todas as respostas HTTP. Portanto, nessa configuração atual, você não precisa ativar esse comportamento. Mas é possível definir explicitamente a configuração de qualquer maneira.

Em segundo lugar, você precisa adicionar o cabeçalho Cache-Control: no-cache, mas somente para seus documentos HTML (index.html, neste caso). A maneira mais fácil de definir esse cabeçalho condicionalmente é escrever um setHeaders function personalizado e, dentro dele, verificar se a solicitação recebida é para um documento HTML.

  • Clique em Remixar para editar para tornar o projeto editável.

A configuração de veiculação estática em server.js começa assim:

app.use(express.static('public'));
  • Faça as mudanças descritas acima e você terá algo parecido com isto:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    }
  },
}));

Configurar cabeçalhos de armazenamento em cache para os URLs com versões

Ao responder a solicitações de URLs que contêm "impressão digital" ou informações de versão e cujo conteúdo nunca muda, adicione Cache-Control: max-age=31536000 às suas respostas. app.15261a07.js e style.391484cf.css se enquadram nessa categoria.

Com base na setHeaders function usada na última etapa, é possível adicionar outra lógica para verificar se uma determinada solicitação é para um URL com versão e, se for o caso, adicionar o cabeçalho Cache-Control: max-age=31536000.

A maneira mais robusta de fazer isso é usar uma expressão regular para verificar se o recurso solicitado corresponde a um padrão específico que você sabe que os hashes se enquadram. No caso deste projeto de exemplo, são sempre oito caracteres do conjunto de dígitos 0 a 9 e das letras minúsculas a a f (ou seja, caracteres hexadecimais). O hash é sempre separado por um caractere . em ambos os lados.

Uma expressão regular que corresponde a essas regras gerais pode ser expressa como new RegExp('\\.[0-9a-f]{8}\\.').

  • Modifique a função setHeaders para que ela fique assim:
app.use(express.static('public', {
  etag: true, // Just being explicit about the default.
  lastModified: true,  // Just being explicit about the default.
  setHeaders: (res, path) => {
    const hashRegExp = new RegExp('\\.[0-9a-f]{8}\\.');

    if (path.endsWith('.html')) {
      // All of the project's HTML files end in .html
      res.setHeader('Cache-Control', 'no-cache');
    } else if (hashRegExp.test(path)) {
      // If the RegExp matched, then we have a versioned URL.
      res.setHeader('Cache-Control', 'max-age=31536000');
    }
  },
}));

Confirmar o novo comportamento usando o DevTools

Com as modificações no servidor de arquivos estático, você pode verificar se os cabeçalhos corretos estão sendo definidos visualizando o app em tempo real com o painel de rede do DevTools aberto.

  • Para visualizar o site, pressione View App. Em seguida, pressione Fullscreen tela cheia.

  • Personalize as colunas que são mostradas no painel de rede para incluir as informações mais relevantes clicando com o botão direito do mouse no cabeçalho da coluna:

Como configurar o painel Network do DevTools.

Aqui, as colunas a que você precisa prestar atenção são Name, Status, Cache-Control, ETag e Last-Modified.

  • Com o DevTools aberto no painel "Network", atualize a página.

Depois que a página carregar, você verá entradas no painel "Network" parecidas com esta:

Colunas do painel Network.

A primeira linha é para o documento HTML para o qual você navegou. Isso é veiculado corretamente com Cache-Control: no-cache. O status da resposta HTTP para essa solicitação é 304. Isso significa que o navegador sabia que não precisava usar o HTML armazenado em cache imediatamente, mas fez uma solicitação HTTP para o servidor da Web usando as informações Last-Modified e ETag para saber se havia alguma atualização no HTML que já estava no cache. A resposta HTTP 304 indica que não há HTML atualizado.

As duas próximas linhas são para os recursos JavaScript e CSS com versão. Elas devem ser exibidas com Cache-Control: max-age=31536000, e o status HTTP de cada uma é 200. Devido à configuração usada, não há uma solicitação real sendo feita para o servidor Node.js. Clicar na entrada mostra mais detalhes, incluindo que a resposta veio "(da cache do disco)".

Um status de resposta de rede 200.

Os valores reais das colunas "ETag" e "Last-Modified" não são muito importantes. O importante é confirmar se elas estão sendo definidas.

Resumindo

Depois de seguir as etapas deste codelab, você já sabe como configurar os cabeçalhos de resposta HTTP em um servidor da Web baseado em Node.js usando o Express, para usar o cache HTTP da melhor forma possível. Você também tem as etapas necessárias para confirmar se o comportamento esperado de armazenamento em cache está sendo usado, pelo painel "Network" no Chrome DevTools.