Resumen

  • HTTP 428 autoriza al origen a rechazar una operación que no trae la condición exigida. La escritura condicional deja de ser una cortesía voluntaria del cliente y pasa a ser política de admisión.
  • If-Match con una etiqueta fuerte es el ejemplo habitual: 428 señala que faltaba la condición; 412 indica que la condición presentada resultó falsa.
  • El código no crea un bloqueo ni resuelve una fusión. Hacen falta validadores correctos, comparación y escritura atómicas, y clientes que reconcilien el estado nuevo antes de reintentar.

Dos respuestas de éxito, una edición desaparecida

Dos operadores leen la versión 7 de una configuración. El primero corrige un valor y guarda la versión 8. El segundo sigue trabajando con su copia anterior y, minutos después, envía el documento completo. Si el servidor sólo comprueba identidad, permisos y formato, ambas operaciones pueden terminar con éxito. Sin embargo, la corrección del primero ya no existe.

La actualización perdida no es necesariamente una avería de transporte. Nace porque la segunda petición describió un destino y un contenido, pero no declaró el estado del que partía su decisión. “Sustituya este recurso” no equivale a “sustitúyalo únicamente si continúa siendo la versión que leí”.

HTTP ya contaba con peticiones condicionales. Los validadores suelen aparecer en la historia del caché: el cliente presenta una etiqueta y evita descargar de nuevo una representación que no cambió. La misma evidencia puede impedir una escritura obsoleta. Faltaba una respuesta precisa para el servidor que se negaba a aceptar la forma incondicional.

El RFC 6585, publicado en abril de 2012, introdujo 428 Precondition Required. El código indica que el servidor de origen exige una petición condicional. Su uso típico es evitar que un cliente lea, modifique y devuelva un estado mientras una tercera parte lo ha cambiado en el intervalo.

La condición como puerta de entrada

Supongamos que una lectura recibe la etiqueta fuerte "v7". Al escribir con If-Match: "v7", el cliente convierte su recuerdo en una afirmación verificable. El origen ejecutará el método sólo si la representación seleccionada conserva esa etiqueta. Si otra escritura produjo "v8", la condición falla y la mutación no debe realizarse.

El cliente cuidadoso podía usar este mecanismo antes de 428. La novedad fue que el origen ganó una forma común de hacerlo obligatorio. El ejemplo del RFC aconseja probar If-Match, y la respuesta debería explicar cómo volver a presentar la operación correctamente.

No existe una única condición para todos los casos. If-Match: * exige que haya una representación actual. If-None-Match: * exige que no exista, una afirmación útil para una creación que no debe pisar otra creación concurrente. Sin etiqueta puede recurrirse a If-Unmodified-Since, aunque la evidencia temporal es menos precisa. El origen debe documentar cuál de estas afirmaciones acepta.

El aporte histórico de 428 es, por tanto, una frontera de autoridad. Quien posee el estado presente puede exigir al escritor que identifique el pasado en el que se apoya.

Ausencia y falsedad producen ramas distintas

428 Precondition Required responde a una cuestión previa: la política requiere una condición, pero la petición no aportó ninguna aceptable. El origen detiene el método antes de sus efectos.

412 Precondition Failed aparece después de la comparación. La petición sí expresó una condición, pero el estado actual no la satisface. El cliente declaró su punto de partida y ese punto ya quedó atrás.

La diferencia tiene valor operativo. Una ola de 428 puede revelar clientes antiguos, documentación ambigua o una pasarela que elimina encabezados. Una ola de 412 puede reflejar sesiones largas, competencia real o etiquetas que cambian por ruido. Mezclar ambas métricas oculta la causa.

428 tampoco es una variante de 409. Un 409 puede describir un conflicto semántico con el recurso. 428 exige la prueba antes de que el origen intente una escritura capaz de causar el conflicto silencioso. Y no equivale al 423 de WebDAV: no informa de un bloqueo ni concede posesión exclusiva.

Por qué If-Match exige identidad fuerte

El actual RFC 9110 ordena usar comparación fuerte con If-Match. Una etiqueta débil puede afirmar que dos representaciones son suficientemente equivalentes para reutilizar una copia. Quien protege una escritura, en cambio, pretende detener el método si cambió cualquier dato de la representación.

Esto vuelve público el diseño del validador. Si el estado protegido cambia y la etiqueta no, una escritura caducada puede pasar. Si la etiqueta cambia por diferencias irrelevantes de serialización, aparecen conflictos falsos. Obligar a usar If-Match sin exponer una etiqueta fuerte utilizable convierte 428 en una prohibición sin salida.

Las fechas son un sustituto limitado. If-Unmodified-Since sirve cuando no hay etiqueta, pero RFC 9110 considera más exacto If-Match e ignora la condición temporal cuando ambas están presentes. La granularidad del reloj y la manera de generar la fecha reducen su capacidad para identificar un estado exacto.

Comparar y confirmar deben ser un solo acto

HTTP sitúa la evaluación en el origen, después de las comprobaciones normales y justo antes de realizar la acción del método. Un intermediario no posee la verdad actual del recurso y no debe decidir si If-Match se cumple; debe reenviar la petición.

La implementación necesita conservar esa proximidad. Si la aplicación compara una versión, abandona la transacción y escribe más tarde, otra operación puede entrar entre comprobación y confirmación. Por fuera todo parece condicional; por dentro reaparece una carrera de tiempo de comprobación frente a tiempo de uso.

La solución es una comparación-y-acción atómica: una columna de versión, compare-and-swap o una transacción equivalente. HTTP especifica la promesa visible, no puede aportar aislamiento a una base de datos que no lo aplica.

También debe coincidir el alcance. Una etiqueta calculada para una vista renderizada quizá no proteja los registros internos que la petición modifica. Una operación que además dispara una cola externa supera otra frontera. 428 no transforma efectos múltiples en una transacción distribuida.

Rechazar no significa reconciliar

Un cliente puede derrotar el objetivo sin infringir la sintaxis: tras recibir 412, obtiene una etiqueta nueva y la adjunta al mismo cuerpo completo y obsoleto. La condición fresca se cumple, pero nadie examinó la edición intermedia. El conflicto visible acaba convertido en un sobrescrito autorizado.

La recuperación suele exigir leer el estado actual, comparar la intención pendiente y decidir si se fusiona, se abandona o se reemplaza de manera consciente. Un parche por campos o una operación conmutativa puede reducir el desacuerdo. En otros recursos, hace falta criterio humano. 428 abre esa rama; no decide por ella.

Además, RFC 6585 declara opcional el código y advierte que los clientes no pueden confiar en su uso para prevenir todas las actualizaciones perdidas. Cuando una API ofrece escritura condicional, el cliente que valora su cambio debe emplearla incluso si el servidor no lo obliga con 428.

Un rechazo que ningún caché debe conservar

Las respuestas 428 no pueden almacenarse en caché. Describen una tentativa que no satisfizo la política de admisión, no una representación reutilizable del recurso. Repetir más tarde un rechazo antiguo permitiría al intermediario ejercer una autoridad que sólo corresponde al origen.

La respuesta debe ayudar: identificar la condición necesaria, mostrar cómo adquirir un validador vigente y señalar que leer de nuevo puede requerir una fusión. El nombre del estado por sí solo no crea una ruta de recuperación.

El registro de IANA mantiene 428 como Precondition Required y remite al RFC 6585. La frase breve conserva una regla profunda: para tener derecho a sustituir el presente, una escritura debe revelar el pasado que la fundamenta.

Fuentes y límites

La base documental es RFC 6585, RFC 9110 y el registro de IANA. Define semántica, orden de evaluación y límites, pero no mide despliegue, pérdidas actuales, soporte universal ni incidentes concretos. 428 no es un bloqueo, una fusión, una transacción ni una garantía de ejecución única.