HTTP en profondeur - 10 - La compression : réduire la taille des réponses

Gzip, Brotli, Accept-Encoding et Content-Encoding : comment compresser les réponses HTTP et quand ne pas le faire.

10 - La compression : réduire la taille des réponses

Ce que tu vas apprendre

  • Le mecanisme Accept-Encoding / Content-Encoding
  • La différence concrète entre gzip et Brotli
  • Quand compresser et quand s'abstenir
  • Comment configurer la compression dans Caddy, Nginx et Node.js
  • Les gains réels en taille

Prerequisites


Un fichier JavaScript de 500 Ko compresse en Brotli fait souvent moins de 100 Ko. Cinq fois moins de donnees sur le réseau, sans perdre un seul octet d'information. La compression HTTP est probablement le meilleur rapport effort/gain de tout le web.

Et pourtant, je croise encore régulièrement des API qui envoient du JSON brut sans compression. Des réponses de 200 Ko qui pourraient faire 15 Ko. Sur mobile avec un réseau moyen, la différence se mesure en secondes.

Le mecanisme : negociation via headers

La compression HTTP repose sur deux headers.

Le client annonce ce qu'il supporte :

GET /app.js HTTP/1.1
Accept-Encoding: gzip, deflate, br

Le serveur choisit un algorithme et compresse la réponse :

HTTP/1.1 200 OK
Content-Encoding: br
Content-Type: application/javascript
Content-Length: 87234

Le br dans Content-Encoding indique que le body est compresse en Brotli. Le navigateur decompresse automatiquement avant de traiter le contenu.

Si le serveur ne supporte aucun des algorithmes demandes, il envoie la réponse sans compression. Pas d'erreur, juste pas de Content-Encoding.

Le header Vary: Accept-Encoding dans la réponse est indispensable pour que les caches intermediaires stockent des versions separees pour chaque encodage.

Gzip vs Brotli

Gzip

Gzip existe depuis 1992. Il est supporte par tous les navigateurs, tous les serveurs, tous les proxies. C'est le choix sur par défaut.

Un fichier JSON de 100 Ko passe typiquement a 15-20 Ko en gzip. Le rapport de compression tourne autour de 70-80% pour du texte.

La compression est rapide. La decompression aussi. Le CPU n'est jamais un goulot d'etranglement avec gzip.

Brotli

Brotli, créé par Google en 2015, compresse mieux que gzip. Sur du texte web, tu gagnes 15 a 25% de taille en plus par rapport a gzip. Cette différence vient de son dictionnaire intégré qui connaît les patterns courants du HTML, CSS et JavaScript.

Le meme JSON de 100 Ko fait 12-15 Ko en Brotli au lieu de 15-20 Ko en gzip. Ca parait modeste en pourcentage, mais multiplie par des millions de requêtes, ca compte.

Le compromis : Brotli est plus lent a compresser, surtout aux niveaux de compression eleves. En pratique, tu utilises Brotli en niveau 4-6 pour la compression a la volee, et en niveau 11 (maximum) pour les assets statiques pre-compresses.

Brotli nécessité HTTPS. Les navigateurs ne supportent br qu'en contexte sécurisé.

En chiffres

Fichier Original Gzip Brotli
React (production) 143 Ko 46 Ko 41 Ko
Bootstrap CSS 231 Ko 34 Ko 27 Ko
JSON API typique 95 Ko 14 Ko 11 Ko
HTML page standard 52 Ko 12 Ko 10 Ko

Quand compresser (et quand ne pas le faire)

Compresser : tout ce qui est du texte. HTML, CSS, JavaScript, JSON, XML, SVG, fichiers source. Les gains sont massifs.

Ne pas compresser : les images (JPEG, PNG, WebP, AVIF), les videos, les fichiers ZIP, les PDFs. Ces formats sont deja compresses. Tenter de les recompresser gaspille du CPU pour un gain nul, voire une taille supérieure.

Seuil minimum : en dessous de 1 Ko, la compression ajoute parfois de la taille a cause des headers de l'algorithme. La plupart des serveurs ne compressent que les réponses au-dessus de 1 Ko.

Configuration dans Caddy

Caddy compresse par défaut avec encode. C'est presque trop simple :

example.com {
    encode zstd gzip
    root * /var/www/html
    file_server
}

Caddy negocie automatiquement l'algorithme avec le client. Brotli n'est pas intégré par défaut dans Caddy, mais le module encode supporte gzip et zstd nativement.

Configuration dans Nginx

nginxgzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
gzip_comp_level 6;
gzip_vary on;

# Brotli (necessite le module ngx_brotli)
brotli on;
brotli_types text/plain text/css application/json application/javascript text/xml;
brotli_comp_level 6;

Le gzip_vary on ajoute automatiquement Vary: Accept-Encoding. Sans ca, un proxy cache pourrait servir une version gzip a un client qui ne le supporte pas.

Compression dans Node.js et Bun

En Node.js, le module compression pour Express :

javascriptconst compression = require("compression");
const express = require("express");

const app = express();
app.use(compression({
  threshold: 1024,
  filter: (req, res) => {
    if (req.headers["x-no-compression"]) return false;
    return compression.filter(req, res);
  }
}));

En pratique, tu laisses rarement Node.js gerer la compression. Un reverse proxy (Caddy, Nginx) devant ton application le fait mieux et libéré le processus Node.js pour le code métier.

Avec Bun, Bun.serve supporte la compression nativement :

javascriptBun.serve({
  fetch(req) {
    return new Response("Hello", {
      headers: { "Content-Type": "text/plain" }
    });
  }
});

Bun gere automatiquement la negociation Accept-Encoding et compresse les réponses textuelles.

Sur paltemps.fr, la compression est geree par le reverse proxy. Le serveur applicatif ne s'en occupe pas du tout. C'est une séparation propre : le code métier produit du contenu, l'infrastructure l'optimise.

Pre-compression des assets statiques

Pour les fichiers statiques (le bundle JS, le CSS), tu peux pre-compresser au moment du build :

bashbrotli -q 11 dist/app.js
gzip -9 dist/app.js

Ca généré app.js.br et app.js.gz. Le serveur sert directement le fichier pre-compresse au lieu de compresser a chaque requête. Le niveau 11 de Brotli prend du temps, mais il ne s'exécuté qu'une fois au build.

Nginx détecté ces fichiers avec gzip_static on et brotli_static on.


Résumé

  • Le client annonce ses algorithmes via Accept-Encoding, le serveur répond avec Content-Encoding
  • Gzip compresse 70-80% du texte, Brotli fait 15-25% de mieux
  • Ne jamais compresser des fichiers deja compresses (images, videos, ZIP)
  • Toujours ajouter Vary: Accept-Encoding pour les caches
  • Pre-compresser les assets statiques au build pour un gain maximal
  • Laisser le reverse proxy gerer la compression plutot que l'application

Article précédent : 09 - TLS et HTTPS

Article suivant : 11 - La negociation de contenu

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.