¿Cómo funciona la compresión HTTP (gzip/brotli), y cuándo realmente ayuda o perjudica?
La compresión intercambia CPU por ancho de banda mediante negociación de contenido — si haces mal el intercambio, quemas ciclos recomprimiendo un JPEG o, peor, abres un canal lateral que filtra secretos sobre TLS.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cómo funciona la compresión HTTP (gzip/brotli), y cuándo realmente ayuda o perjudica?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Por qué los entrevistadores hacen esta pregunta
"Activa gzip" es un cambio de configuración de una línea que la mayoría de los ingenieros ha hecho sin que nunca se les pida justificarlo. La versión senior de esta pregunta comprueba si entiendes la compresión como un intercambio negociado de CPU por ancho de banda, y no como un interruptor que siempre es seguro activar — porque la misma configuración que le quita un 70% a un payload JSON también puede quemar CPU inútilmente en un endpoint de imágenes, o, en el peor de los casos, abrir un canal lateral real de fuga de información sobre TLS.
#Negociación de contenido: el cliente ofrece, el servidor decide
La compresión en la web se negocia por solicitud, no se configura una vez y se olvida. El cliente lista lo que puede decodificar en el header de solicitud Accept-Encoding (gzip, deflate, br, típicamente en orden de preferencia del cliente); el servidor elige uno —o ninguno— y marca su elección con el header de respuesta Content-Encoding. Si la respuesta del servidor varía según ese header de solicitud (que varía, en el momento en que la compresión es condicional), también debe enviar Vary: Accept-Encoding, o una caché compartida delante de él (un CDN, un proxy inverso) puede servirle una respuesta codificada en brotli a un cliente que solo entiende gzip, o peor, un cuerpo sin comprimir a un cliente que esperaba la semántica de headers de compresión que nunca recibió.
#Cómo comprimen realmente gzip y brotli
Gzip (y el deflate crudo, muy relacionado) está construido sobre LZ77 — desliza una ventana sobre los datos buscando secuencias de bytes repetidas y reemplaza las repeticiones con referencias cortas hacia atrás, y luego codifica el resultado con Huffman para exprimir aún más las frecuencias de símbolos restantes. Por eso la razón de compresión depende tanto de la redundancia: JSON, HTML, CSS y JS están llenos de puntuación, claves y espacios en blanco repetidos, así que comprimen extremadamente bien, a menudo 60-80% más chicos. Brotli, desarrollado por Google, se construye sobre la misma base de LZ77 más codificación entrópica, pero agrega un diccionario estático grande preentrenado con contenido web común (etiquetas HTML, palabras clave de JS, frases comunes) y un modelado de contexto más sofisticado, por lo que brotli en un ajuste comparable típicamente supera la razón de gzip en otro 15-25% sobre texto — al costo de ser más lento para comprimir en sus niveles de calidad más altos, aunque la velocidad de descompresión es comparable a la de gzip.
Ambos algoritmos exponen una perilla de calidad/nivel que intercambia tiempo de CPU por razón de compresión: gzip va de 1 (más rápido, peor razón) a 9 (más lento, mejor razón), brotli va de 0 a 11. Para contenido comprimido una vez y servido muchas veces —activos estáticos—, usar el nivel más alto no cuesta nada en tiempo de solicitud y es dinero gratis. Para contenido comprimido de nuevo en cada solicitud —respuestas dinámicas de API—, un ajuste de nivel medio (gzip 6, brotli 4-5) suele ser el intercambio correcto, ya que exprimir el último par de puntos porcentuales de tamaño no vale duplicar el costo de CPU por solicitud.
#Cuándo la compresión realmente ayuda
La compresión justifica su costo de CPU cuando el payload es tipo texto y tiene redundancia real que explotar: respuestas JSON de API, documentos HTML, CSS, JavaScript, SVG y texto plano caen todos en esta categoría, típicamente reduciéndose a la mitad o más. También importa más justo donde el ancho de banda es el cuello de botella respecto a la CPU — clientes móviles en redes limitadas, clientes geográficamente distantes que pagan latencia completa de ida y vuelta por cada byte, o endpoints de alto tráfico donde la factura agregada de ancho de banda eclipsa la factura agregada de CPU.
#Cuándo la compresión perjudica
Dos modos de falla aparecen constantemente en sistemas reales. Primero, recomprimir formatos binarios que ya están comprimidos —JPEG, PNG, MP4, la mayoría de los códecs modernos de video/audio, ZIP, PDF— desperdicia CPU con poca o ninguna ganancia, porque esos formatos ya eliminaron la redundancia de la que depende la compresión; en el peor caso, la compresión agrega algunos bytes de framing y la salida "comprimida" termina siendo más grande que la entrada. Segundo, comprimir respuestas muy pequeñas cuesta más en CPU y overhead propio de la codificación (el header/footer de gzip, la configuración del diccionario de brotli) de lo que ahorra en bytes transferidos, por lo que los despliegues reales fijan un umbral mínimo de tamaño (a menudo alrededor de 1 KB) por debajo del cual simplemente se omite la compresión.
#Configurándolo de verdad
# SolicitudGET /api/products HTTP/1.1Host: api.shop.exampleAccept-Encoding: gzip, deflate, br# RespuestaHTTP/1.1 200 OKContent-Type: application/jsonContent-Encoding: brVary: Accept-EncodingContent-Length: 4213
// Express — middleware de compresión, ajustado para omitir payloads chicos y ya comprimidosimport express from "express";import compression from "compression";const app = express();app.use(compression({threshold: 1024, // los cuerpos de menos de 1 KB no valen la pena comprimirfilter: (req, res) => {const contentType = String(res.getHeader("Content-Type") || "");if (/image|video|zip|pdf/i.test(contentType)) return false; // ya está comprimidoreturn compression.filter(req, res);},}));app.get("/api/products", (req, res) => {res.json(bigProductCatalog); // el middleware maneja la negociación y la codificación});
gzip on;gzip_types application/json text/css application/javascript text/html image/svg+xml;gzip_min_length 1024;gzip_comp_level 6;gzip_vary on;# brotli normalmente necesita el módulo ngx_brotli compiladobrotli on;brotli_types application/json text/css application/javascript text/html image/svg+xml;brotli_comp_level 5;
#gzip vs. brotli, lado a lado
| gzip | brotli | |
|---|---|---|
| Algoritmo base | LZ77 + Huffman | LZ77 + Huffman + diccionario estático web + modelado de contexto |
| Razón típica vs. gzip | referencia | ~15-25% más chico en texto |
| Velocidad de compresión a máxima calidad | Rápido incluso en nivel 9 | Notablemente más lento en calidad 10-11 |
| Velocidad de descompresión | Rápida | Comparable a gzip |
| Soporte de navegadores | Universal | Universal en navegadores modernos (sobre HTTPS) |
| Mejor uso | Respuestas dinámicas comprimidas al vuelo | Activos estáticos precomprimidos en el build |
🧠 Check your understanding
0/2 · 0/2 answered1. Un endpoint de API sirve una respuesta de error JSON de 400 bytes. La compresión está activada en todo el servidor sin umbral de tamaño. ¿Cuál es el resultado probable?
2. ¿Por qué comprimir una imagen JPEG con gzip suele ser inútil?