Pular para o conteúdo
.NETCache HTTP, expiração e validação (ETag)
Módulo 06APIs em Produção

Cache HTTP, expiração e validação (ETag)

avancado 50 min de leitura·Atualizado · .NET 9
Resumo

Caching reduz latência e carga reaproveitando respostas. Cobrimos os dois modelos — expiração (Cache-Control) e validação (ETag/If-None-Match) — e o middleware de cache do ASP.NET Core.

1. Objetivos de Aprendizagem#

  • Diferenciar cache de cliente, proxy e servidor.
  • Aplicar o modelo de expiração com Cache-Control.
  • Implementar o modelo de validação com ETag.

2. Pré-requisitos#

  • Endpoints GET (Módulo 18).

3. Conceito#

Dois modelos complementares:

  • Expiração: a resposta é considerada "fresca" por um tempo (Cache-Control: max-age=60). Enquanto fresca, o cliente nem contata o servidor.
  • Validação: ao expirar, o cliente pergunta "mudou?" enviando If-None-Match: <etag>. Se não mudou, o servidor responde 304 Not Modified sem corpo.

O porquê: economizar banda e processamento; 304 é muito mais barato que reenviar o recurso.

Fluxo de validação com ETag:

Carregando diagrama…

4. Mão na Massa#

4.1. Setup#

O ASP.NET Core oferece o middleware de response caching e output caching. Usaremos o cache HTTP + ETag.

C#
builder.Services.AddResponseCaching();
// ou, mais moderno:
builder.Services.AddOutputCache();

4.2. Implementação Passo a Passo#

  1. Pipeline:
C#
app.UseResponseCaching();      // ou app.UseOutputCache();
  1. Expiração por ação:
C#
[HttpGet]
[ResponseCache(Duration = 60)] // Cache-Control: public,max-age=60
public async Task<IActionResult> Get() => Ok(await _service.Produto.GetAllAsync(false));
  1. Validação com ETag (esboço via cabeçalhos):
C#
[HttpGet("{id:guid}")]
public async Task<IActionResult> GetOne(Guid id)
{
    var produto = await _service.Produto.GetAsync(id, false);
    var etag = $"\"{produto.Version}\""; // ex.: rowversion

    if (Request.Headers.IfNoneMatch == etag)
        return StatusCode(StatusCodes.Status304NotModified);

    Response.Headers.ETag = etag;
    return Ok(produto);
}

4.3. Executando#

Shell
curl -i http://localhost:5000/api/produtos/{id}          # recebe ETag
curl -i -H 'If-None-Match: "v1"' http://localhost:5000/api/produtos/{id}  # 304 se igual

5. Exemplo Completo#

Combine os modelos: Cache-Control: max-age=30 para frescor curto + ETag para revalidação barata após expirar.

6. Boas Práticas e Armadilhas#

FaçaEvite
Usar private em respostas por usuáriopublic em dados personalizados/autenticados
Gerar ETag a partir de uma versão real do recursoETag aleatório que nunca casa
Cachear apenas GET/HEADCachear respostas de escrita
Atenção

nunca marque como public (cacheável por proxies) respostas que dependem de autenticação/usuário — isso pode entregar dados de um usuário a outro.

7. Segurança e Produção#

  • Respostas autenticadas devem ser Cache-Control: private, no-store quando contiverem dados sensíveis.
  • Cache mal configurado é uma fonte clássica de vazamento de dados entre usuários.

8. Exercícios#

  • Fácil: adicione max-age=120 a um endpoint de leitura pública.
  • Médio: implemente ETag baseado em rowversion e retorne 304.
  • Desafio: compare ResponseCaching com OutputCache (.NET 7+) e justifique a escolha.

9. Resumo#

Caching combina expiração (Cache-Control) e validação (ETag/304). Cacheie só leituras, marque dados de usuário como private/no-store e gere ETags a partir de versões reais.

10. Próximos Passos#

Módulo 39: rate limiting e throttling.

11. Referências#

38-01 — Cache HTTP, expiração e validação (ETag) | Curso ASP.NET Core