---
title: Introducción a la compresión de datos en la web
description: Optimiza el tamaño y velocidad de tu aplicación web gracias al uso correcto de la compresión de datos.
url: https://www.felixsanz.dev/es/articulos/introduccion-a-la-compresion-de-datos-en-la-web
language: es
published: 2017-10-04
updated: 2017-10-04
tags:
  - networking
  - performance
alternate-en: https://www.felixsanz.dev/articles/introduction-to-data-compression-on-the-web
---

# Introducción a la compresión de datos en la web

## Introducción

La compresión web, esa pequeña e incomprendida funcionalidad que utilizamos constantemente para enviar y recibir datos de manera más rápida y **generando un volumen de datos menor**.

En este artículo veremos cómo funciona y las distintas opciones de las que disponemos.

## Negociación

El cliente y el servidor acuerdan qué metodo de compresión utilizar mediante la **negociación**.

### Accept-Encoding

Cuando el cliente solicita un recurso web al servidor, puede indicarle qué formatos de compresión desea utilizar. Esto lo hace a través de la cabecera `Accept-Encoding` ([RFC 7231, sección 5.3.4](https://tools.ietf.org/html/rfc7231#section-5.3.4)), indicando los algoritmos de compresión que acepta. Ejemplo:

```
GET /encrypted-area HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip, deflate
```

En este caso el cliente indica al servidor que acepta los métodos de compresión `gzip` y `deflate`. El orden es importante ya que indica la **preferencia del cliente** (`gzip` sería la primera opción a utilizar y `deflate` la segunda).

Para controlar la preferencia también puede utilizarse el modificador `;q=`, indicando un [valor cualitativo](https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9) (*q-value*). Esto expresa la prioridad en unidades "*weight*" que van desde 0 hasta 1. Ejemplo:

```
GET /encrypted-area HTTP/1.1
Host: www.example.com
Accept-Encoding: deflate;q=0.8, gzip;q=1.0
```

En este caso, a pesar de que `gzip` se encuentra segundo en la lista, sería el primero en cuanto a prioridad.

### Content-Encoding

Tras la petición, llega la respuesta. En este caso el servidor es quién decide el método de compresión a utilizar. Realmente, el servidor puede hacer lo que le plazca, pero lo normal sería respetar los deseos del cliente y utilizar el algorimo de compresión con mayor prioridad especificado por el cliente. En el ejemplo anterior sería `gzip`. Si `gzip` no estuviera disponible se utilizaría `deflate`, y así sucesivamente. Si ninguno estuviera disponible, el servidor no debería comprimir el contenido.

Aparte de comprimir el cuerpo de la respuesta, el servidor añade la cabecera `Content-Encoding` ([RFC 7231, sección 3.1.2.2](https://tools.ietf.org/html/rfc7231#section-3.1.2.2)) en la que especifica el algoritmo de compresión que finalmente se ha utilizado. Ejemplo:

```
HTTP/1.1 200 OK
Content-Length: 309
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
```

> [!WARNING]
> **¡Recuerda!**
> No hay que confundir `Content-Type` con `Content-Encoding`. Aunque se comprima la respuesta, ésta sigue teniendo un formato, como por ejemplo: `text/html`, `video/mp4` o `image/jpg`. Por lo tanto, no olvides especificar la cabecera `Content-Type` para indicar el contenido del mensaje, esté comprimido o no.

## zlib

Jean-loup Gailly y Mark Adler crearon en 1995 la librería de compresión [zlib](https://zlib.net/). Con el mismo nombre nació el formato zlib (especificado en el [RFC 1950](https://tools.ietf.org/html/rfc1950)), que consiste en una cabecera (***header***), un cuerpo (***body***) comprimido mediante un algoritmo de compresión (generalmente `deflate`, aunque se pueden implementar otros) y por último incluye una suma de verificación (***checksum***) en formato Adler-32.

Así pues, la librería zlib producía ficheros en formato `zlib`.

Esta breve información nos será útil para entender los varios algoritmos de compresión.

## Formatos de compresión

Formatos de compresión hay unos cuantos pero sin duda `gzip` domina la web.

Los valores posibles en las cabeceras `Accept-Encoding` y `Content-Encoding` son: `deflate`, `gzip`, `br`, `identity`, `compress` y `*`.

Vamos a echarles un vistazo.

### deflate

El caso de `deflate` es curioso a la vez que confuso. Está definido como:

> El formato "zlib" definido en RFC 1950 en combinación con el mecanismo de compresión "deflate" descrito en RFC 1951.  
>   
> *The "zlib" format defined in RFC 1950 in combination with the "deflate" compression mechanism described in RFC 1951.*
> 
> [RFC 2616](http://www.ietf.org/rfc/rfc2616.txt)

Vamos por partes para intentar entenderlo mejor.

Resulta que según el RFC 2616, `deflate` equivale al formato `zlib`, comprimiendo el cuerpo utilizando el algortimo `deflate` (es decir, ningún otro algoritmo puede ser utilizado).

¿Confuso verdad? Resulta que `deflate` es tanto un **formato** como un **algoritmo** utilizado dentro de ese formato.

Esto llevó a la confusión también a los ingenieros de Microsoft que implementaron el formato, por lo que durante años los navegadores no sabían si `deflate` se refería al formato o al algoritmo de compresión, por lo que **funcionaban por descarte**: si no era uno, era otro.

Esta ambigüedad a la hora de definir el formato `zlib`/`deflate` provocó que el formato `gzip` se extendiera rápidamente y se acabase convirtiendo en el rey de la compresión web.

Para entenderlo mejor, veamos la [implementación](https://nodejs.org/api/zlib.html) en Node.js de la librería zlib.

Resulta que tenemos estos dos métodos:

-   **[zlib.Deflate](https://nodejs.org/api/zlib.html#zlib_class_zlib_deflate)**: *Compress data using deflate*.
-   **[zlib.DeflateRaw](https://nodejs.org/api/zlib.html#zlib_class_zlib_deflateraw)**: *Compress data using deflate, and do not append a zlib header*.

Ya lo habrás adivinado, pero el método `zlib.Deflate` se refiere al formato `deflate` (incluyendo la cabecera y la suma de verificación), mientras que el método `zlib.DeflateRaw` se refiere al algoritmo de compresión en sí, sin ninguna cabecera ni envoltorio de ningún tipo.

#### Cómo diferenciar Deflate y DeflateRaw

Primero, vamos a ver que ocurre cuando comprimimos la cadena `foo` utilizando ambos métodos:

```javascript
zlib.deflateSync('foo')
```

```
<Buffer 78 9c 4b cb cf 07 00 02 82 01 45>
```

```javascript
zlib.deflateRawSync('foo')
```

```
<Buffer 4b cb cf 07 00>
```

El resultado de `deflate` como formato produce una **cabecera** con los bytes `78 9c`, un **cuerpo** que contiene los bytes `4b cb cf 07 00` (en común con `deflate` como algoritmo) y una **suma de verificación** con los bytes `02 82 01 45`.

Es en los bytes de cabecera, más concretamente en el **primer byte** (78 en nuestro ejemplo) en donde está la distinción.

Un byte se compone de dos [nibbles](https://es.wikipedia.org/wiki/Nibble). Al ser `78` un valor hexadecimal, el `7` es un nibble y el `8` es el otro nibble. Siendo el primero el alto (más significante) y el segundo el bajo (menos significante), aunque este orden [depende](https://es.wikipedia.org/wiki/Endianness) de la arquitectura/plataforma en la que te encuentres, pero vamos a obviar esto.

Si el nibble bajo (el segundo) es un `8`, entonces estamos ante el **formato** `deflate`/`zlib`, mientras que si no es un `8`, estaremos ante el algoritmo de compresión. Es una [regla](https://stackoverflow.com/a/37528114/3181234) que siempre se cumple.

Por lo tanto, en nuestro ejemplo podemos ver claramente cual es un formato `deflate` y cual es un algoritmo de compresión `deflate` (conocido en la implementación de zlib de Node.js como `deflateRaw`).

### gzip

Basado en el algoritmo `deflate`, [gzip](http://www.gzip.org/zlib/rfc-gzip.html) es un formato abierto que comprime el mensaje utilizando el algoritmo `LZ77` y añade, al igual que el formato `zlib`, una cabecera y una suma de verificación, aunque ésta en formato CRC-32.

La cabecera del formato `gzip` contiene **más bytes** de los que contiene el formato `zlib` (en total 12 bytes más). Además, la suma de verificación utilizando CRC-32 es más lenta de generar que mediante Adler-32, pero estas desventajas **apenas son perceptibles** con la potencia de los dispositivos de hoy en día. Ésto, sumado a que evitaremos la confusión del formato/algoritmo `deflate`, ha convertido a gzip en la opción ideal para adoptar cuando hablamos de compresión web.

### Brotli

Brotli es un formato de compresión creado por Google en 2015 para comprimir fuentes para la web en formato `WOFF`, pero rápidamente encontró su sitio en el campo de la compresión web por sus ventajas. Utiliza un algoritmo de compresión propio, basado en `LZ77`.

Su compatibilidad en navegadores es actualmente del [62%](http://caniuse.com/#search=brotli), más que suficiente teniendo en cuenta que si Brotli no estuviera disponible se utilizaría el siguiente de la lista.

> [!NOTE]
> **Actualización 2023**
> Hoy en día su compatiblidad es prácticamente total, situándose en un 96.45%.

En las cabeceras HTTP `Accept-Encoding` y `Content-Encoding` debe especificarse con el valor `br`.

En cuanto a las ventajas frente a `gzip`, promete en torno a un **20% extra de compresión** siendo prácticamente igual de rápido en compresión/descompresión.

### \* (asterisco)

Cuando se utiliza el valor `*` se está indicando al servidor que se acepta compresión de datos pero no se especifica ninguna preferencia en cuanto al formato.

Éste es el valor por defecto cuando omitimos la cabecera `Accept-Encoding`.

### identity

La función de `identity` es la de indicar de manera explícita al servidor que no se desea ninguna compresión.

### compress

Este formato basado en el algoritmo [LZW](https://es.wikipedia.org/wiki/LZW) cayó en desuso debido a problemas de patentes y apenas quedan navegadores que lo soporten.

### Zstandard

Facebook posee un proyecto open source llamado [Zstandard](https://github.com/facebook/zstd) (**zstd**), que promete **mejores resultados que Brotli**, tanto en compresión como en velocidad. Desgraciadamente, por el momento no cuenta con soporte en ningún navegador así que el uso de este formato no es realmente válido en compresión web. Aún así, se merece una mención.

## Comprimiendo lo comprimido

Hay formatos de archivo que pueden estar ya comprimidos como por ejemplo algunas imágenes `PNG` y `GIF` o las tipografías web en formato `WOFF`.

En el caso de que estos datos ya estuvieran comprimidos, comprimirlos nuevamente sería un **malgasto de recursos**, ya que el tamaño final sería **incluso superior** (añadiendo una cabecera y una suma de verificación innecesarias) y además el servidor estaría empleando ciclos de CPU en comprimir algo que no va a aportar ningún beneficio.

Tampoco es favorable comprimir dos veces el mismo fichero. Si algo ya está comprimido, mejor dejarlo así.

## Conclusión

Aplicar de manera inteligente la compresión de datos en nuestras aplicaciones web puede **ahorrarnos mucha transferencia de datos** mientras conseguimos un extra de velocidad para nuestros usuarios.

En cuanto a los formatos, lo óptimo sería hacer uso de nuevas opciones como Brotli para optimizar los recursos al máximo. Como la compresión web **degrada fácilmente**, no hay motivo para dejar de lado a los navegadores más antiguos, así que podemos utilizar `gzip` como segunda opción y dejar que sea el cliente el que elija.
