Como configurar o comportamento de armazenamento em cache HTTP

Este codelab mostra como alterar os cabeçalhos de armazenamento em cache HTTP retornados por um servidor da Web baseado em Node.js, executando o framework de exibição Express (em inglês). Ele também mostrará como confirmar se o comportamento de armazenamento em cache esperado está realmente sendo aplicado, usando o painel "Network" no DevTools do Chrome.

Conhecer o projeto de exemplo

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

  • server.js contém o código Node.js que disponibiliza o conteúdo do app da Web. Ele usa Express para processar solicitações e respostas HTTP. Especificamente, o express.static() é usado para exibir todos os arquivos locais no diretório público. Por isso, 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 versão como parte do URL.
  • public/app.15261a07.js e public/style.391484cf.css são os recursos de JavaScript e CSS do app da Web. Cada arquivo tem um hash nos URLs, correspondente ao conteúdo deles. O index.html é responsável por acompanhar qual URL com controle de versões específico será carregado.

Configurar cabeçalhos de cache para nosso HTML

Ao responder a solicitações de URLs que não contêm informações de controle 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 padronizadas para true para todas as respostas HTTP. Portanto, na configuração atual, você não precisa ativar esse comportamento. Mas você pode ser explícito na configuração mesmo assim.

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

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

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

app.use(express.static('public'));
  • Faça as alterações descritas acima e você terá algo parecido com:
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 controle de versão

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

Com base no setHeaders function usado na última etapa, você pode adicionar outra lógica para verificar se uma determinada solicitação é para um URL com controle de versão e, em caso afirmativo, adicionar o cabeçalho Cache-Control: max-age=31536000.

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

Uma expressão regular que corresponda 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');
    }
  },
}));

Confirme o novo comportamento usando o DevTools

Com as modificações no servidor de arquivos estáticos em vigor, é possível verificar se os cabeçalhos corretos estão sendo definidos visualizando o app ativo com o painel Network do DevTools aberto.

  • Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia modo tela cheia.

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

Configurando o painel Network do DevTools.

Aqui, as colunas a serem examinadas 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 for carregada, você verá entradas no painel "Rede" como estas:

Colunas do painel "Rede".

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

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

Status de resposta de rede 200.

Os valores reais das colunas "ETag" e "Última modificação" não importam muito. O importante é confirmar se eles estão sendo configurados.

Resumindo

Após concluir as etapas deste codelab, você sabe como configurar os cabeçalhos de resposta HTTP em um servidor da Web baseado em Node.js usando o Express para melhorar o uso do cache HTTP. 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.