HTTP 304 Not Modified, simulado requisição a requisição
HTTP 304 Not Modified
HTTP 304 Not Modified: ETag e If-None-Match explicados | We.Inc
Simule uma requisição condicional: defina o ETag e o Last-Modified do servidor, o If-None-Match e o If-Modified-Since do navegador, e veja 304 ou 200 com o motivo.
Uma resposta 304 Not Modified diz ao navegador que a cópia em cache ainda está atual, então o servidor não envia o corpo de novo. Ela responde a um GET ou HEAD condicional que trouxe If-None-Match ou If-Modified-Since. Um 304 é boa notícia, não um erro: economiza banda enquanto o arquivo em cache continua sendo usado.
Os pares de validadores por trás de um 304
O servidor envia
O navegador devolve
O servidor responde 304 quando
ETag: "v2"
If-None-Match: "v2"
Uma das tags listadas corresponde ao ETag atual (comparação fraca)
Last-Modified: <date>
If-Modified-Since: <date>
O recurso não mudou desde essa data
Ambos
Ambos
If-None-Match decide; If-Modified-Since é ignorado
Preencha o que o servidor tem no momento e o que o navegador envia, e o simulador aplica as regras de precedência da especificação HTTP. Ele mostra o status que o servidor deve devolver e qual cabeçalho decidiu. Deixe um campo vazio para omitir esse cabeçalho.
Defina o valor de ETag e de Last-Modified que o servidor tem para o arquivo neste momento.
Defina os cabeçalhos If-None-Match e If-Modified-Since que o navegador envia a partir do cache.
Leia o status e o motivo: qual cabeçalho foi avaliado e por que correspondeu ou não.
Mude o ETag do servidor para ver como um deploy transforma a próxima requisição em 200.
Um 304 precisa repetir cabeçalhos como Cache-Control, ETag, Vary e Date que um 200 traria, para que o cache possa atualizar os metadados guardados.
Nomes de assets com fingerprint, como app.3f9a1c.js, mais um max-age longo evitam totalmente a revalidação. Deixe a revalidação por ETag para HTML e respostas de API.
ETags fracos começam com W/ e prometem equivalência semântica, não igualdade de bytes. Eles ainda funcionam com If-None-Match porque esse cabeçalho usa comparação fraca.
No DevTools, uma linha 304 com tamanho de transferência pequeno é o navegador revalidando com sucesso. Desative o cache no painel Network para forçar respostas 200 completas enquanto depura.
Perguntas frequentes
Uma resposta 304 é um erro?
Não. É um status da classe de redirecionamento que significa que a cópia em cache pode ser usada. O navegador mostra a página a partir do cache, e só os cabeçalhos passaram pela rede.
Uma resposta 304 pode ter corpo?
Não. A especificação diz que uma resposta 304 termina no fim da seção de cabeçalhos e não pode ter conteúdo.
Qual prevalece, If-None-Match ou If-Modified-Since?
If-None-Match. Quando uma requisição traz os dois, um servidor que suporta entity tags avalia If-None-Match e ignora If-Modified-Since, porque as tags detectam mudanças que uma data com precisão de um segundo não detecta.
Por que recebo 200 em vez de 304 depois de cada deploy?
O deploy mudou o arquivo ou o ETag dele, então a tag que o navegador guarda não corresponde mais. Esse é o comportamento correto. Se arquivos que não mudaram também perdem o 304, verifique se os seus servidores geram ETags diferentes para o mesmo conteúdo.
POST pode devolver 304?
Não. If-None-Match e If-Modified-Since só produzem 304 para GET e HEAD. Para outros métodos, uma condição que falha gera 412 Precondition Failed.
Como a revalidação funciona
Quando uma resposta em cache fica desatualizada, o navegador não a joga fora. Ele pergunta ao servidor se a cópia ainda serve enviando os validadores que guardou: o ETag como If-None-Match e a data Last-Modified como If-Modified-Since.
Se nada mudou, o servidor responde 304 com cabeçalhos novos e sem corpo, e o navegador continua usando a cópia. Se algo mudou, o servidor envia um 200 normal com o conteúdo novo.
Tags fortes e fracas
Uma tag forte como "v2" promete que os bytes são idênticos. Uma tag fraca como W/"v2" promete só que o conteúdo é equivalente. If-None-Match faz comparação fraca, então W/"v2" e "v2" contam como correspondência ali; If-Match faz comparação forte e não contaria.
A troca na rede
Primeira visita: 200 com validadores
O servidor entrega um ETag e uma data Last-Modified junto com o conteúdo.
Visita seguinte: 304 sem corpo
O navegador devolve a tag guardada e recebe só cabeçalhos.
Respondendo você mesmo a requisições condicionais
Servidor http do Node com ETag baseado em hash do conteúdo
Calcula o hash do corpo, compara com If-None-Match e envia 304 sem corpo quando corresponde.
Simulador de requisição condicional
O que o servidor tem agora
O que o navegador envia
ETag
Last-Modified
If-None-Match
If-Modified-Since
Resposta do servidor
If-None-Match lista uma tag que corresponde ao ETag atual na comparação fraca, então a cópia em cache está atual.
If-None-Match é *, e o recurso existe, então a condição é falsa.
Nenhuma tag em If-None-Match corresponde ao ETag atual, então o servidor envia o conteúdo novo. If-Modified-Since não é verificado.
Não há If-None-Match, e Last-Modified não é posterior a If-Modified-Since.
Não há If-None-Match, e Last-Modified é posterior a If-Modified-Since.
If-Modified-Since está presente, mas uma das duas datas não pode ser lida, então o cabeçalho é ignorado.
A requisição não tem validadores, então é uma requisição comum.