ETag es un encabezado de respuesta HTTP que contiene un identificador único de la versión de un recurso. El servidor genera un ETag como un hash del contenido o un número de versión y lo devuelve al cliente junto con los datos. En solicitudes posteriores, el cliente envía este identificador en el encabezado If-None-Match, permitiendo al servidor verificar si el recurso ha cambiado. Según MDN Web Docs, 2025, ETag es la base del mecanismo de solicitudes GET condicionales en HTTP. Las solicitudes condicionales con ETag reducen el volumen de datos transferidos durante la sincronización de aplicaciones móviles hasta en un 90%.
Puntos clave
ETag (Entity Tag) es un encabezado HTTP de la familia de encabezados condicionales que valida los recursos en caché. El servidor calcula un ETag como un hash (MD5, SHA-256) o un número de versión del recurso y lo devuelve en respuesta a una solicitud GET. El cliente almacena el ETag junto con los datos y lo envía en el encabezado If-None-Match en solicitudes posteriores. Si el contenido del recurso no ha cambiado, el servidor responde con un estado 304 Not Modified sin cuerpo de respuesta.
Para las aplicaciones móviles, ETag es críticamente importante porque reduce la cantidad de datos descargados. En cada inicio o sincronización, la aplicación verifica la frescura de los recursos con una solicitud If-None-Match — en lugar de cargar datos completos, recibe un 304 y usa la copia local. Según Google Chrome Team (2024), el uso de ETag en API móviles reduce el tamaño promedio de respuesta en un 87% para listas y en un 94% para objetos individuales.
ETag se genera en el servidor y puede ser tanto determinístico (idéntico para contenido idéntico, útil para cachés compartidos) como único por respuesta (para validación estricta). En las API REST diseñadas para sincronización móvil, la combinación más común es un hash del contenido y un número de versión del registro en la base de datos.
ETags fuertes (strong ETag) son identificadores que cambian con cualquier modificación del contenido, incluidas las insignificantes (espacios, formato). Formato: “abc123def” (entre comillas dobles, sin prefijo). Los ETags fuertes garantizan que el recurso no ha cambiado byte por byte. Son obligatorios para solicitudes de rango (Range requests) y para verificar la integridad de descargas parciales.
ETags débiles (weak ETag) son identificadores con el prefijo W/, por ejemplo W/“abc123def”. Permiten que el recurso sea semánticamente equivalente incluso si la representación de bytes difiere. Los ETags débiles son útiles para servidores que generan dinámicamente respuestas con diferentes espacios o formato pero el mismo significado. Sin embargo, los ETags débiles no soportan solicitudes de rango.
Comparación de tipos de ETag:
| Característica | ETag fuerte | ETag débil |
|---|---|---|
| Formato | “hash” | W/“hash” |
| Sensibilidad | Byte por byte | Semántica |
| Solicitudes Range | Soportadas | No soportadas |
| Caché CDN | Ideal | Limitada |
| Sincronización | Alta precisión | Permite colisiones |
Last-Modified es un encabezado HTTP que indica la fecha y hora de la última modificación del recurso. El cliente lo envía de vuelta en el encabezado If-Modified-Since. Last-Modified es más simple de implementar (el servidor solo necesita una fecha), pero tiene limitaciones fundamentales: resolución de un segundo (dos cambios en el mismo segundo son indistinguibles) y la imposibilidad de determinar si el contenido ha cambiado si la marca de tiempo es la misma (por ejemplo, después de restaurar una copia de seguridad).
ETag resuelve estos problemas: el hash del contenido cambia con cualquier modificación independientemente del tiempo. Por lo tanto, las API REST modernas usan una combinación de ambos encabezados: ETag para validación precisa y Last-Modified para filtrado aproximado en CDN. Apache HTTP Server y Nginx generan ambos encabezados para archivos estáticos por defecto.
Para aplicaciones móviles con sincronización, ETag es más crítico porque permite detectar conflictos de edición. Si un cliente envía una solicitud PUT con If-Match: “etag”, el servidor rechaza la solicitud si el recurso fue modificado por otro cliente (bloqueo optimista). Last-Modified no puede garantizar tal confiabilidad debido a la precisión de segundo nivel.
Veamos una implementación del lado del cliente de ETag en una aplicación móvil usando Kotlin con Retrofit y OkHttp. En cada solicitud GET, el cliente guarda el ETag de la respuesta, y en la siguiente solicitud lo envía en el encabezado If-None-Match. Si el servidor devuelve 304, los datos no se descargan nuevamente.
Configuración del cliente OkHttp con almacenamiento en caché de ETag:
class EtagClient {
private val etagCache =
mutableMapOf<String, String>()
private val client = OkHttpClient.Builder().build()
suspend fun fetchWithEtag(
url: String
): Result<String> {
val request = Request.Builder()
.url(url)
.header("If-None-Match",
etagCache[url] ?: "")
.build()
val response = client.newCall(request).await()
return when (response.code) {
304 -> Result.success(
"not_modified")
200 -> {
response.header("ETag")?.let {
etagCache[url] = it
}
Result.success(response.body?.string()
?: "")
}
else -> Result.failure(
Exception("HTTP ${response.code}"))
}
}
}
El cliente guarda el ETag después de una respuesta 200 exitosa y lo envía en el encabezado If-None-Match en la siguiente solicitud. Con una respuesta 304, el cliente sabe que la versión local está actualizada y no gasta tráfico en volver a descargar. Este patrón reduce los costos de red de la aplicación móvil en un 80–90% para recursos solicitados con frecuencia.
ETag es un mecanismo clave para optimizar la sincronización de aplicaciones móviles con API REST. En un esquema de sincronización estándar, el cliente primero solicita una lista de recursos con validación ETag — si ningún recurso ha cambiado, el servidor devuelve 304 y el cliente completa la sincronización. Si hay cambios, el servidor devuelve solo los recursos modificados. Este enfoque se llama sincronización delta y es críticamente importante para dispositivos móviles con tráfico limitado.
En escenarios de bloqueo optimista, ETag se usa para prevenir conflictos de Lost Update. Cuando un cliente envía una solicitud PUT para actualizar un recurso, incluye el encabezado If-Match: “etag”. Si el ETag no coincide (otro cliente ya ha modificado el recurso), el servidor responde con 412 Precondition Failed, y el cliente debe volver a obtener la versión actual y reintentar la modificación. Este enfoque garantiza la consistencia de los datos sin bloqueos a nivel de base de datos.
Para sistemas distribuidos con modo fuera de línea, ETag se usa en combinación con la Resolución de Conflictos. El cliente se sincroniza obteniendo ETags actuales para todos los recursos. Al enviar cambios, el servidor verifica If-Match — si el ETag no coincide, se registra un conflicto que se resuelve según la estrategia elegida (LWW, Merge). Según el Postman API Report (2025), el 67% de las API REST de producción para aplicaciones móviles usan ETag como mecanismo principal de validación de versiones.
Preguntas frecuentes
ETag es un encabezado de respuesta HTTP que contiene un identificador único de versión del recurso. El cliente lo usa para solicitudes condicionales: si el recurso no ha cambiado, el servidor devuelve 304 Not Modified sin cuerpo de respuesta, ahorrando tráfico.
ETag usa un hash del contenido para una comparación precisa. Last-Modified se basa en la fecha de modificación con precisión de segundo. ETag es más confiable para detectar cambios reales y soporta bloqueo optimista mediante If-Match.
ETags fuertes (sin prefijo) distinguen recursos byte por byte. ETags débiles (con prefijo W/) permiten equivalencia semántica. Los fuertes son necesarios para solicitudes de rango, los débiles para contenido generado dinámicamente.
ETag reduce el tráfico en un 80–90%: el cliente verifica la frescura de todos los recursos mediante If-None-Match, descargando solo los que han cambiado. Sin ETag, el cliente descargaría datos completos en cada sincronización, desperdiciando tráfico y batería.
El servidor calcula un ETag como un hash (MD5, SHA-256) del contenido de la respuesta o usa un número de versión del registro en la base de datos. En Spring Boot, la anotación @Cacheable con etag = true es suficiente. En Express.js, el middleware etag está habilitado por defecto.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también