Resumo

  • O 428 permite que a origem recuse uma alteração sem a condição exigida. A escrita condicional deixa de depender apenas da cautela do cliente e passa a ser política de entrada do recurso.
  • O caso clássico combina If-Match com ETag forte: 428 quer dizer que a condição faltou; 412 quer dizer que a condição apresentada foi avaliada como falsa.
  • O status não cria trava, fusão nem transação. A proteção depende de validadores úteis, comparação e commit atômicos e reconciliação real antes de uma nova tentativa.

O desaparecimento que duas respostas verdes escondem

Duas pessoas abrem a versão 7 de um documento. A primeira corrige uma passagem e salva a versão 8. A segunda continua trabalhando na cópia antiga e envia depois o documento inteiro. Se o servidor verifica apenas credenciais, formato e destino, as duas gravações podem parecer bem-sucedidas. A correção mais nova, porém, desaparece.

Esse é o problema de lost update. Não exige ataque nem falha de rede. A segunda escrita informa o que quer colocar e onde, mas não declara em qual estado se baseou. “Substitua este recurso” é uma autorização muito mais ampla que “substitua apenas se ele ainda for a versão que eu li”.

O HTTP já tinha campos condicionais. Eles ficaram famosos na validação de cache, quando uma etiqueta permite reaproveitar uma cópia sem transferir o corpo outra vez. O mesmo mecanismo pode guardar uma alteração. Faltava uma resposta específica para a origem que considerava a forma incondicional insuficiente.

Em abril de 2012, o RFC 6585 definiu 428 Precondition Required. O código indica que o servidor de origem exige uma requisição condicional. O uso típico descrito é impedir que um cliente leia, edite e devolva um estado enquanto outra parte o modificou nesse intervalo.

Da boa prática para a regra de admissão

Quando a leitura entrega a ETag forte "v7", a escrita com If-Match: "v7" transforma memória em afirmação verificável. A origem só executa o método se a representação selecionada continuar com aquela etiqueta. Caso outra gravação tenha criado "v8", a condição é falsa e o método não pode acontecer.

Clientes cuidadosos já podiam usar isso. O 428 acrescentou a autoridade para a origem tornar a condição obrigatória. O exemplo do RFC aconselha tentar If-Match, e a resposta deve explicar como reapresentar o pedido com sucesso.

Isso não torna If-Match a resposta universal. If-Match: * afirma que uma representação precisa existir. If-None-Match: * afirma que ela não pode existir, útil para impedir que duas criações se sobreponham. Sem ETag, If-Unmodified-Since pode fornecer uma condição temporal. A política do recurso precisa dizer qual evidência aceita.

O passo histórico é a mudança de controle: quem possui o estado atual passa a poder exigir que o escritor revele o estado passado que sustenta sua decisão.

Condição ausente e condição falsa

O 428 responde antes da avaliação: a política exige uma condição, mas a requisição não trouxe uma condição aceitável. A origem não inicia o método com efeitos.

O 412 Precondition Failed responde depois da avaliação. A condição veio, a origem comparou e descobriu que ela não corresponde ao presente. O cliente nomeou o passado; o passado já mudou.

Separar os códigos melhora a investigação. Muitos 428 podem apontar para SDK antigo, documentação ruim ou gateway removendo campos. Muitos 412 podem revelar edições longas, concorrência legítima ou ETags sensíveis a ruído. Juntar os números apaga a diferença entre desconhecer o contrato e perder uma corrida.

O 428 também não é um 409 especializado. O 409 pode descrever incompatibilidade semântica com o estado atual. O 428 exige evidência antes de uma escrita que poderia esconder o conflito. Tampouco equivale ao 423 do WebDAV: não há trava ou posse exclusiva.

A ETag precisa ser forte de verdade

O atual RFC 9110 determina comparação forte para If-Match. Uma ETag fraca pode dizer que duas representações são equivalentes o bastante para cache. Para proteção de escrita, a intenção é parar o método sempre que os dados da representação mudaram.

Gerar o validador torna-se parte do contrato externo. Se o estado protegido muda e a ETag não, a origem admite atualização vencida. Se a ETag muda por ordenação ou serialização irrelevante, o sistema cria conflitos falsos. Exigir If-Match sem expor uma ETag forte utilizável transforma o 428 em beco sem saída.

Condições de data são menos precisas. If-Unmodified-Since pode cumprir papel parecido quando não há etiqueta, mas RFC 9110 trata If-Match como substituto mais exato e ignora a data se ambos aparecem. Granularidade de relógio e formação do timestamp limitam a identidade temporal.

A comparação não pode se separar do commit

O HTTP coloca a avaliação na origem, depois das verificações normais e imediatamente antes da ação do método. Um intermediário não deve decidir se If-Match corresponde ao estado da origem, pois não possui essa verdade. Sua função é encaminhar.

O código interno deve preservar essa proximidade. Se o serviço compara a versão, encerra a transação e só depois grava, uma alteração concorrente pode entrar entre os dois passos. A troca HTTP parece segura; a implementação recria a corrida entre verificar e usar.

Comparar e agir precisam formar uma decisão atômica, por coluna de versão, compare-and-swap ou transação equivalente. O HTTP define o compromisso observável, mas não oferece atomicidade à camada de dados.

O escopo também importa. A ETag de uma página renderizada pode não proteger vários registros de origem. Uma alteração que ainda dispara mensagem externa ultrapassa outro limite. O 428 não transforma efeitos múltiplos em uma transação distribuída.

Rejeitar não é fazer merge

Depois de um 412, um cliente pode buscar apenas uma ETag nova e anexá-la ao mesmo corpo completo e antigo. A condição atual passa, mas a mudança intermediária nunca foi analisada. O conflito que estava visível vira uma sobrescrita formalmente autorizada.

Recuperar exige normalmente reler o presente, comparar a intenção pendente e decidir por fusão, desistência ou substituição explícita. Patch por campo ou operação comutativa pode reduzir o conflito. Em outros casos, uma pessoa precisa escolher. O 428 abre esse caminho, mas não executa a decisão.

RFC 6585 também deixa o código opcional e avisa que clientes não podem depender dele para evitar toda atualização perdida. Se a API oferece uma escrita condicional, o cliente responsável deve usá-la sem esperar uma repreensão do servidor.

Uma resposta que o cache não pode guardar

O RFC proíbe armazenar respostas 428 em cache. O bloqueio descreve uma tentativa específica que não satisfez a política, não uma representação durável do alvo. Reproduzir um 428 antigo permitiria ao intermediário inventar uma decisão que pertence à origem.

A resposta deve orientar: qual condição falta, como obter um validador atual e por que uma releitura talvez exija reconciliação. Apenas devolver o nome do status não cria uma rota de recuperação.

O registro da IANA mantém 428 como Precondition Required, referenciado ao RFC 6585. A frase curta preserva uma regra ampla: antes de trocar o presente, a escrita precisa tornar público o passado que lhe dá fundamento.

Fontes e limites

As fontes são RFC 6585, RFC 9110 e o registro IANA. Elas estabelecem semântica, ordem de avaliação e limites, mas não medem adoção, prejuízo atual, suporte universal ou incidentes específicos. O 428 não é trava, merge, transação ou garantia de execução única.