Cache-Control — o que é, diretivas e gerenciamento de cache

Autor: IT Sectr Publicado: 2026-03-09 Tempo de leitura: 9 min

Cache-Control é um cabeçalho HTTP que define as regras de cache de recursos no cliente, servidores proxy e CDNs usando um conjunto de diretivas. Ao contrário do obsoleto cabeçalho Expires, Cache-Control suporta dezenas de combinações: max-age define o tempo de vida em segundos, private e public controlam a disponibilidade do cache, no-cache e no-store — verificação forçada. De acordo com Google Web Dev (2025), a configuração correta do Cache-Control pode reduzir o tempo de carregamento de páginas em 50-80% para visitas repetidas. Isso torna o cabeçalho criticamente importante para o desempenho de aplicações web e móveis.

Principais conclusões

  • Cache-Control — um cabeçalho HTTP com diretivas que controlam o cache no cliente, proxy e CDN
  • max-age — uma diretiva chave que define o tempo de vida do recurso em segundos sem revalidação
  • private vs public — private permite cache apenas no cliente, public também em proxies e CDNs
  • no-cache vs no-store — no-cache exige validação antes do uso, no-store proíbe cache completamente
  • s-maxage — substitui max-age para caches compartilhados sem afetar navegadores

O que é Cache-Control?

Cache-Control é um cabeçalho HTTP, padronizado em HTTP/1.1 (RFC 7234), que permite ao servidor especificar como e por quanto tempo clientes, proxies e CDNs podem armazenar em cache a resposta. Ao contrário de Expires (HTTP/1.0), Cache-Control usa diretivas — comandos de texto combinados com vírgulas: Cache-Control: public, max-age=3600, must-revalidate. O cabeçalho fornece controle refinado sobre cada elo da cadeia de cache.

O cache é um dos mecanismos fundamentais de desempenho de aplicações web e móveis. Sem ele, cada solicitação do usuário iria diretamente ao servidor, causando carga excessiva e latência. Cache-Control define três níveis de cache: navegador/aplicativo (cache privado), servidores proxy (cache compartilhado) e CDN (cache distribuído). Cada nível interpreta as diretivas de forma diferente.

A configuração incorreta do Cache-Control é uma das causas mais comuns de problemas de desempenho. Um cache muito agressivo faz com que os usuários vejam dados desatualizados. Um cache muito fraco leva a solicitações excessivas ao servidor e carregamento lento. De acordo com a Akamai (2025), otimizar o Cache-Control para conteúdo estático reduz a carga do servidor em 70-90% e melhora o tempo de carregamento em 40-60% para usuários móveis.

História do cabeçalho

Cache-Control apareceu em HTTP/1.1 (RFC 2616, 1999) como substituto do Expires. O Expires tinha um problema fundamental: usava uma data absoluta que dependia dos fusos horários do servidor e do cliente. O Cache-Control resolveu esse problema mudando para o tempo relativo (max-age em segundos a partir do momento em que a resposta é recebida). Mais tarde, no RFC 7234 (2014), novas diretivas foram adicionadas: immutable para ativos estáticos, stale-while-revalidate e stale-if-error para validação diferida.

Diretivas de Cache-Control

Cache-Control inclui mais de 10 diretivas divididas em três grupos: diretivas de solicitação (cliente → servidor), diretivas de resposta (servidor → cliente) e extensões. Na prática, o desenvolvimento móvel usa 6-7 diretivas de resposta principais que cobrem 95% dos cenários de cache. Vamos examinar cada uma com exemplos e recomendações.

DiretivaSignificadoExemplo
max-ageTempo de vida em segundos a partir da respostamax-age=3600 — 1 hora
s-maxagemax-age para cache compartilhado (proxy, CDN)s-maxage=86400 — 1 dia para CDN
publicPermite armazenamento em cache por todos (incluindo proxies)public, max-age=3600
privatePermite cache apenas para o navegador/aplicativoprivate, max-age=600
no-cacheNão usar sem validação (304 necessário)no-cache
no-storeProibir completamente o armazenamento em cacheno-store
must-revalidateApós max-age, deve revalidar com a origemmax-age=3600, must-revalidate
immutableO recurso não mudará (para ativos estáticos versionados)max-age=31536000, immutable

max-age é a diretiva mais importante. Ela proíbe o cliente de fazer uma solicitação ao servidor pelo tempo especificado. Para ativos estáticos (CSS, JS, imagens), o max-age geralmente é definido de 1 dia a 1 ano. Para respostas de API — de 0 segundos (dados sempre atualizados) a 5-10 minutos (dados de referência). s-maxage permite definir diferentes tempos de vida para CDN e navegador: a CDN armazena uma cópia por 1 dia, o navegador por 1 hora.

no-cache vs no-store

Essas duas diretivas são frequentemente confundidas. no-cache não proíbe o cache — ele exige validar a cópia em cache a cada uso por meio de uma solicitação condicional (If-Modified-Since ou If-None-Match). Se o servidor responder com 304 — o cliente usa o cache. Se 200 — ele atualiza. no-store, por outro lado, proíbe completamente salvar a resposta em qualquer cache, incluindo disco e memória. Use no-store apenas para dados confidenciais — tokens, dados de pagamento, documentos pessoais.

Cache-Control vs Expires

O cabeçalho Expires (HTTP/1.0) também especifica o tempo de vida do recurso, mas usa uma data absoluta: Expires: Thu, 03 Jul 2026 12:00:00 GMT. Cache-Control max-age usa tempo relativo a partir do momento da resposta. A diferença é crítica para sistemas distribuídos: se o servidor e o cliente estão em fusos horários diferentes, o Expires pode ser interpretado incorretamente. O Cache-Control não tem esse problema — 3600 segundos são sempre 3600 segundos.

Quando ambos os cabeçalhos estão presentes, Cache-Control tem prioridade sobre Expires. Isso é definido no RFC 7234: “Se uma resposta incluir um campo Cache-Control com a diretiva max-age, o destinatário DEVE ignorar o campo Expires.” Na prática, é recomendado não retornar Expires para clientes modernos, pois Cache-Control cobre todos os cenários de Expires. No entanto, para compatibilidade retroativa com proxies e navegadores antigos, ambos os cabeçalhos podem ser retornados.

Expires sobreviveu principalmente para conteúdo estático em Nginx e Apache — esses servidores adicionam automaticamente ambos os cabeçalhos. Se seu projeto encontrar Expires sem Cache-Control, substitua-o por Cache-Control com max-age: a precisão do controle de cache melhora e a dependência do fuso horário é eliminada. Para migração, basta configurar o servidor para adicionar Cache-Control em vez de Expires.

nginx
# Nginx: Cache-Control para arquivos estáticos
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public, immutable, max-age=2592000";
}

# Políticas diferentes para diferentes tipos de conteúdo
location /api/config {
    expires -1;
    add_header Cache-Control "no-cache, must-revalidate";
}

location /api/static-data {
    expires 5m;
    add_header Cache-Control "public, max-age=300";
}

Na configuração do Nginx, arquivos estáticos (CSS, JS, imagens) são definidos com Cache-Control por 30 dias com o atributo immutable — este atributo informa ao navegador que o recurso nunca muda nesta URL (versionamento via hash no nome do arquivo). Os endpoints de API usam no-cache para dados dinâmicos e public com um max-age curto para dados de referência — listas frequentemente solicitadas e raramente alteradas.

Cache em aplicações móveis

Em aplicações móveis, o Cache-Control desempenha um papel especial devido às limitações das redes móveis: alta latência, conexão instável, limites de tráfego. Um cache adequado permite exibir dados ao usuário instantaneamente, mesmo offline, e atualizá-los em segundo plano. OkHttp no Android e URLSession no iOS têm sistemas de cache integrados que respeitam o Cache-Control.

OkHttp usa CacheInterceptor, que lê o Cache-Control da resposta e gerencia automaticamente o cache. Se o servidor retornou Cache-Control: max-age=3600, o OkHttp não fará uma solicitação ao servidor por uma hora. Após a expiração do max-age, o OkHttp envia uma solicitação condicional com If-Modified-Since e If-None-Match. Configuração de cache no OkHttp: OkHttpClient.Builder().cache(Cache(directory, maxSize)).

kotlin
fun createCachedClient(cacheDir: File): OkHttpClient {
    return OkHttpClient.Builder()
        .cache(Cache(cacheDir, 10L * 1024 * 1024))
        .addNetworkInterceptor { chain ->
            val response = chain.proceed(chain.request())
            response.newBuilder()
                .header("Cache-Control",
                    "public, max-age=300")
                .removeHeader("Pragma")
                .build()
        }
        .build()
}

O código cria um OkHttpClient com cache de 10 MB e substitui o Cache-Control através do NetworkInterceptor. Se o servidor não retornar Cache-Control ou usar Expires, o interceptor adiciona public, max-age=300 (5 minutos). O interceptor remove o cabeçalho obsoleto Pragma (HTTP/1.0) para compatibilidade. O cache no iOS funciona de forma semelhante através do URLCache.shared com as configurações memoryCapacity e diskCapacity.

Modo offline e stale-while-revalidate

A diretiva stale-while-revalidate permite mostrar ao usuário um cache obsoleto enquanto o aplicativo busca dados atualizados em segundo plano. Isso proporciona um efeito de resposta instantânea: o usuário vê o conteúdo imediatamente e, após um segundo, ele é atualizado para a versão atual. Suportado pelo OkHttp a partir da versão 3.10 e pelo URLCache no iOS 14+. Exemplo: Cache-Control: max-age=3600, stale-while-revalidate=300 — 1 hora de cache atualizado, depois 5 minutos exibindo dados obsoletos com atualização em segundo plano.

Exemplos de configuração de Cache-Control

Diferentes tipos de recursos exigem diferentes estratégias de cache. Vamos ver as configurações ideais para cenários típicos no desenvolvimento móvel. Para conteúdo estático com hash no nome do arquivo (bundle.abc123.js), você pode definir max-age de até 1 ano com immutable. Para listas de API que são raramente atualizadas (direórios, categorias) — max-age de 5 minutos a 1 hora com stale-while-revalidate.

Tipo de recursoCache-ControlExplicação
Ativos estáticos versionadospublic, max-age=31536000, immutable1 ano, arquivos não mudam (hash na URL)
Ativos estáticos não versionadospublic, max-age=86400, must-revalidate1 dia com revalidação forçada após
API: dados de referênciapublic, max-age=600, stale-while-revalidate=6010 minutos de cache + 1 minuto obsoleto
API: dados do usuárioprivate, max-age=601 minuto, apenas para um usuário específico
API: dados confidenciaisno-storeProibição completa de cache
Páginas HTMLno-cache, must-revalidateValidação em cada solicitação, 304 se inalterado

Importante lembrar da segurança: para respostas contendo dados pessoais do usuário, sempre defina private. Sem essa diretiva, um proxy público (por exemplo, corporativo) pode armazenar a resposta em cache e entregá-la a outro usuário. Para tokens de autenticação e informações de pagamento, use no-store — nem mesmo um cache privado deve armazenar esses dados em disco.

Depuração de cache

Para verificar a correção do Cache-Control, use o cabeçalho Age (quantos segundos o cache foi armazenado) e X-Cache (hit/miss na CDN). No navegador — a guia Network, a coluna Size mostra “from disk cache” ou “304 Not Modified”. Se um recurso deve ser armazenado em cache, mas é carregado toda vez, verifique se o servidor está adicionando Cache-Control: no-cache ou Pragma: no-cache junto com suas diretivas.

Perguntas frequentes

Qual é a diferença entre max-age e s-maxage?

max-age se aplica a todos os caches (incluindo navegadores), s-maxage se aplica apenas a caches compartilhados (proxies, CDNs). Se s-maxage for especificado, a CDN ignora max-age e usa s-maxage. Isso permite definir diferentes tempos de vida para o navegador e a CDN.

Pode-se cancelar o cache após enviar Cache-Control?

Não, após enviar uma resposta com max-age, o cliente não fará uma solicitação até que o temporizador expire. Para invalidação imediata do cache, você precisa alterar a URL do recurso (adicionar versão/hash) e enviar notificações push ou mensagens WebSocket para reinicialização forçada.

O que é a diretiva immutable?

A diretiva immutable (RFC 8246) informa ao navegador que o recurso nunca mudará nesta URL. O navegador nem tenta fazer uma solicitação condicional ao atualizar a página — ele usa o cache até a expiração do max-age. Funciona apenas com arquivos versionados.

Como o Cache-Control afeta o SEO?

O Googlebot leva o Cache-Control em consideração: cache longo acelera o rastreamento repetido. noindex com cache rápido é aceitável. no-store pode desacelerar a indexação porque o Googlebot carregará a página do zero toda vez. Um max-age muito curto aumenta a carga do servidor durante o rastreamento.

Como configurar Cache-Control no Express.js?

Através do helmet ou middleware: res.set('Cache-Control', 'public, max-age=3600'). Para arquivos estáticos, use express.static com o parâmetro maxAge: express.static('public', {maxAge: '1y'}). Para rotas dinâmicas — individualmente em cada manipulador.

Resumo

  • Cache-Control — o principal cabeçalho HTTP para gerenciamento de cache com um sistema flexível de diretivas
  • max-age — tempo de vida em segundos a partir da resposta; diretiva chave para todos os cenários de cache
  • private vs public — private apenas para o cliente, public para proxies e CDNs; afeta a segurança dos dados
  • no-cache exige validação, no-store proíbe completamente o cache; propósitos diferentes, não confunda
  • s-maxage — substitui max-age para caches compartilhados, útil para dividir políticas de navegador/CDN
  • stale-while-revalidate — exibe cache obsoleto com atualização em segundo plano para UX instantânea
  • Recomendação — configure Cache-Control para cada tipo de recurso no servidor e no cliente HTTP móvel

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também