HTTP/2: cómo multiplexa peticiones y comprime cabeceras con HPACK
@programacionLo esencial
- HTTP/2 se estandarizó en mayo de 2015 como RFC 7540, basado en el protocolo SPDY de Google.
- Multiplexa varios streams sobre una sola conexión TCP, evitando abrir 6 conexiones paralelas por dominio como en HTTP/1.1.
- HPACK (RFC 7541) comprime cabeceras con una tabla estática de 61 entradas más una tabla dinámica compartida entre cliente y servidor.
- Cada mensaje se parte en frames binarios (DATA, HEADERS, SETTINGS, WINDOW_UPDATE) identificados por un stream ID.
- En la práctica, los navegadores solo negocian HTTP/2 sobre TLS vía la extensión ALPN.
- Server Push permitía al servidor enviar recursos sin que el cliente los pidiera, pero Chrome eliminó el soporte en 2022 por bajo uso real.
- El head-of-line blocking sigue existiendo a nivel TCP: un paquete perdido bloquea todos los streams de la conexión.
Cargá una página con 80 recursos por HTTP/1.1 y el navegador abre hasta 6 conexiones TCP paralelas por dominio para no esperar en fila. HTTP/2 resuelve ese cuello de botella con un truco simple: manda todas las peticiones por la misma conexión, entrelazadas.
El problema de HTTP/1.1: una petición a la vez por conexión
En HTTP/1.1 cada conexión TCP procesa las peticiones en orden estricto. Si pedís un archivo CSS de 2 MB antes que un ícono de 3 KB, el ícono espera a que termine el CSS. Este fenómeno se llama head-of-line blocking a nivel de aplicación.
Los navegadores lo mitigaron abriendo varias conexiones TCP simultáneas por dominio (típicamente 6). Funciona, pero cada conexión nueva repite el handshake TCP y, si es HTTPS, también el handshake TLS: más latencia, más uso de memoria en el servidor.
Qué es la multiplexación en HTTP/2
HTTP/2 divide una única conexión TCP en múltiples streams lógicos independientes. Cada petición y su respuesta viajan en un stream identificado por un número impar (si lo abre el cliente) o par (si lo abre el servidor).
Los mensajes de distintos streams se entrelazan (se multiplexan) en la misma conexión: el navegador pide el HTML, el CSS y el JS a la vez, y el servidor va intercalando fragmentos de las tres respuestas sin que ninguna bloquee a las otras. Esto está definido en la especificación oficial de la RFC 7540.
Frames y streams: cómo se parte cada mensaje
HTTP/2 es un protocolo binario. Cada mensaje se trocea en frames, cada uno con un tipo, una longitud y un stream ID en su cabecera de 9 bytes. Los tipos principales son HEADERS (cabeceras), DATA (cuerpo), SETTINGS (parámetros de la conexión), WINDOW_UPDATE (control de flujo) y RST_STREAM (cancelar un stream sin cerrar la conexión).
Podés ver los frames reales con curl:
curl -v --http2 https://developer.mozilla.org/ 2>&1 | grep -i "http2"La salida muestra líneas como h2h HEADERS y Using HTTP2, confirmando que la negociación se hizo por ALPN durante el handshake TLS.
HPACK: comprimiendo cabeceras repetitivas
Un navegador manda las mismas cabeceras (user-agent, cookie, accept-language) en cada petición dentro de una misma página. HTTP/1.1 las repite en texto plano cada vez. HTTP/2 usa HPACK, definido en la RFC 7541, para evitar esa repetición.
HPACK combina dos mecanismos. Primero, una tabla estática de 61 cabeceras comunes (como :method: GET o content-type: text/html) que ambos extremos conocen de antemano, así que se envían como un solo índice numérico en vez de texto. Segundo, una tabla dinámica que cliente y servidor van llenando con las cabeceras que ya vieron en la conexión actual: si una cabecera ya se envió antes, la siguiente vez solo se manda su índice.
Cuando una cabecera no está en ninguna tabla, HPACK la codifica con Huffman, un algoritmo de compresión que asigna códigos más cortos a los caracteres más frecuentes en cabeceras HTTP (letras minúsculas, guiones, dígitos).
Ejemplo práctico: un servidor HTTP/2 en Node.js
El módulo nativo http2 de Node.js expone streams directamente:
const http2 = require('node:http2');
const fs = require('node:fs');
const server = http2.createSecureServer({
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem'),
});
server.on('stream', (stream, headers) => {
stream.respond({
':status': 200,
'content-type': 'text/plain',
});
stream.end('Hola desde HTTP/2');
});
server.listen(8443);El evento stream se dispara una vez por cada petición que llega, aunque todas compartan la misma conexión TCP subyacente. Node.js maneja el framing y HPACK internamente; el código de aplicación solo ve headers y datos ya decodificados.
Server Push: la función que casi nadie usa ya
HTTP/2 incluía Server Push, pensado para que el servidor enviara recursos (como un CSS) sin esperar a que el navegador los pidiera. En la práctica resultó difícil de cachear bien y generaba más tráfico del necesario cuando el navegador ya tenía el recurso en caché. Chrome eliminó el soporte en 2022 y otros navegadores siguieron el mismo camino.
Limitación real: el head-of-line blocking a nivel TCP
Multiplexar streams dentro de HTTP/2 no elimina el problema por completo: TCP entrega los bytes en orden estricto. Si un paquete se pierde, TCP retiene todos los bytes posteriores (de todos los streams) hasta retransmitirlo, aunque pertenezcan a un stream distinto que no tenía nada que ver con el paquete perdido. En redes con pérdida de paquetes (wifi congestionado, móvil), esto puede anular buena parte de la ganancia de HTTP/2.
Esta limitación es la razón por la que HTTP/3 reemplaza TCP por QUIC sobre UDP, donde cada stream se recupera de pérdidas de forma independiente.
Conclusión
HTTP/2 resolvió dos problemas concretos de HTTP/1.1: dejó de forzar una petición a la vez por conexión gracias a la multiplexación de streams, y dejó de repetir cabeceras completas en cada petición gracias a HPACK. Sigue siendo el protocolo dominante en la web actual, aunque su límite de fondo (TCP entrega en orden) es exactamente lo que HTTP/3 vino a corregir.
📖 Versión extendida con más detalle: https://elsolitario.org/2026/08/07/http2-multiplexacion-hpack-headers/?utm_source=telegraph&utm_medium=instant_view&utm_campaign=programacion