Cache HTTP, expiração e validação (ETag)
ResumoCaching 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 responde304 Not Modifiedsem corpo.
O porquê: economizar banda e processamento; 304 é muito mais barato que reenviar o recurso.
Fluxo de validação com ETag:
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.
builder.Services.AddResponseCaching();
// ou, mais moderno:
builder.Services.AddOutputCache();
4.2. Implementação Passo a Passo#
- Pipeline:
app.UseResponseCaching(); // ou app.UseOutputCache();
- Expiração por ação:
[HttpGet]
[ResponseCache(Duration = 60)] // Cache-Control: public,max-age=60
public async Task<IActionResult> Get() => Ok(await _service.Produto.GetAllAsync(false));
- Validação com
ETag(esboço via cabeçalhos):
[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#
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ça | Evite |
|---|---|
Usar private em respostas por usuário | public em dados personalizados/autenticados |
Gerar ETag a partir de uma versão real do recurso | ETag aleatório que nunca casa |
Cachear apenas GET/HEAD | Cachear respostas de escrita |
Atençãonunca 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-storequando 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=120a um endpoint de leitura pública. - Médio: implemente
ETagbaseado emrowversione retorne304. - Desafio: compare
ResponseCachingcomOutputCache(.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#
- Microsoft Learn — Cache de resposta no ASP.NET Core
- Microsoft Learn — Output caching
- MDN — Cache-Control e ETag