Cache et compression des pages web avec Gzip ou Deflate en HTTP
Article par dew (Alsacréations, Strasbourg)
Intérêt de la compression
De nos jours, l'accent est souvent mis sur la performance des sites et les économies de bande passante notamment sur mobile. Les temps d'accès et de téléchargement se mesurent (très précisément avec de nombreux outils) en millisecondes. De nombreuses recommandations provenant de Google et Yahoo font mention de la compression des pages avant leur transit sur le réseau.
- Le serveur compresse les données (code HTML, CSS, JavaScript...)
- Les fichiers transitent par le réseau via HTTP
- Le navigateur décompresse à la volée les données avant de les interpréter

Ce qui représentait une charge supplémentaire pour les serveurs web à l'époque où leur puissance était moindre, peut désormais devenir négligeable en regard des améliorations apportées, notamment pour les navigateurs mobiles. Si la compression impose une charge trop importante à votre serveur, il est possible de pré-compresser les contenus, les placer en cache et les délivrer directement.
Ces techniques qui sont prévues depuis HTTP/1.1 (1999) peuvent tout à fait être mises en œuvre pour les documents HTML mais aussi CSS, XML ou JavaScript. Il est inutile de s'en servir pour les fichiers binaires (images, vidéos, PDF...). Elles ne vous dispensent pas de réduire initialement la taille des fichiers HTML ou CSS (les "minifier") en appliquant d'autres critères tels que la suppression des espaces excédentaires ou des commentaires inutiles.

Navigateurs
La première interrogation - dans le monde impitoyable de la création web et des guerres entre navigateurs modernes et antiques - concerne le support de cette fonctionnalité. Or, ici, bonne nouvelle : on peut considérer que la totalité des navigateurs supportent la décompression des pages avec HTTP/1.1 :
![]()
- Microsoft Internet Explorer depuis 4.0*
- Opera depuis 5.12
- Firefox toutes versions
- Google Chrome toutes versions
- Safari toutes versions
- Netscape depuis 4.06
- Tous les navigateurs mobiles
* avec quelques petits bugs jusqu'aux versions 5.0 et 6.0 comprises
De plus, il incombe aux navigateurs d'envoyer un en-tête HTTP indiquant les types de pages compressées supportées . Si cet en-tête ne figure pas dans ceux reçus par le serveur, il lui suffit de ne pas activer la compression.
GET / HTTP/1.1
Host: www.alsacreations.com
Accept-Encoding: gzip
User-Agent: Firefox/3.6
Le serveur répond alors de la même manière, grâce à Content-Encoding, et en faisant suivre par le contenu compressé de la page.
HTTP/1.1 200 OK
Server: Apache
Content-Type: text/html
Content-Encoding: gzip
Content-Length: 13337
...
Deux formats coexistent :
- Deflate, algorithme qui couple LZ77 et le codage de Huffman (zlib)
- Gzip, évolution de Deflate, un peu plus performant, mieux supporté, plus répandu
Mise en place au niveau des serveurs web

Attention : les indications suivantes doivent être ajustées selon votre configuration et vos besoins.
Apache est équipé de modules de compression :
- dans les anciennes versions 1.3 : mod_gzip ou mod_deflate
- depuis la version 2.0 et supérieures : du module officiel mod_deflate qui utilise zlib et remplace mod_gzip
Ces modules sont désactivés par défaut, mais peuvent être activés dans la configuration générale du serveur si vous y avez accès. Par défaut mod_deflate permet de spécifier les types de fichiers à compresser à la volée grâce à la directive AddOutputFilterByType DEFLATE. Une fois ces modules disponibles vous pouvez également exploiter les fichiers .htaccess dans chaque répertoire pour plus de souplesse (voir au point suivant).
Activation des modules pour Apache 2
Si votre serveur le permet, vous devez accéder en ligne de commande avec les droits root pour activer les modules nécessaires avec la commande a2enmod :
a2enmod headers
a2enmod deflate
/etc/init.d/apache2 restart
# ou... service apache2 restart
Manuellement en ajoutant aussi un fichier dans mods-available/deflate.load et un lien symbolique vers celui-ci dans mods-enabled/, ou une ligne dans httpd.conf :
LoadModule deflate_module /usr/lib/apache2/modules/mod_deflate.so
Sous Windows, il faudra indiquer le chemin du fichier .dll éponyme. Attention : si un lien symbolique vers mod_deflate.conf est déjà présent dans mods-enabled avec une directive de configuration générale, il est possible que tous vos fichiers soient déjà délivrés compressés. Faites un test avant tout - voir en fin d'article.
Puis il faut ajouter des directives à la configuration (par exemple dans un fichier situé dans /etc/apache2/conf.d/) pour compresser des types de fichiers bien spécifiques, dans un répertoire spécifique lui aussi. Ceci est recommandé lorsque l'on place toutes les feuilles de style dans un répertoire indépendant, ainsi que les JavaScripts, car le but n'est pas de (re)compresser tous les fichiers hébergés sur le serveur web mais de se focaliser sur l'essentiel. Il est donc possible d'indiquer <Location /css> pour n'appliquer ces règles que sur ce répertoire (on considère ici l'URL) et ses descendants, ou d'utiliser <Directory /chemin/absolu/vers/css> si l'on se réfère au système de fichiers.
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
DeflateCompressionLevel 9
</IfModule>
<Location />
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom_xml
AddOutputFilterByType DEFLATE application/x-javascript
# Pour les proxies
Header append Vary User-Agent env=!dont-vary
</Location>
- DeflateCompressionLevel
- Indique le facteur de compression, de 1 (faible, par défaut) à 9 (fort) : n'est applicable qu'au niveau de la configuration globale du serveur, pas dans les fichiers .htaccess
- AddOutputFilterByType DEFLATE text/html
-
Applique la compression sur les fichiers de type mime
text/html - SetOutputFilter DEFLATE
- Active le filtre compression.
N'oubliez pas de redémarrer (restart) ou recharger (reload) Apache après chaque modification de la configuration.
/etc/init.d/apache2 restart
# ou service apache2 restart
Apache 1.3
Pour activer le module dans le fichier de configuration httpd.conf, ajoutez la ligne :
LoadModule gzip_module modules/mod_gzip.so
Puis configuration, semblable à celle mentionnée auparavant :
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_can_negotiate Yes
mod_gzip_static_suffix .gz
AddEncoding gzip .gz
mod_gzip_update_static No
mod_gzip_command_version '/mod_gzip_status'
mod_gzip_temp_dir /tmp
mod_gzip_keep_workfiles No
mod_gzip_minimum_file_size 500
mod_gzip_maximum_file_size 500000
mod_gzip_maximum_inmem_size 60000
mod_gzip_min_http 1000
mod_gzip_handle_methods GET POST
mod_gzip_item_exclude reqheader "User-agent: Mozilla/4.0[678]"
mod_gzip_item_include file \.html$
mod_gzip_item_include file \.htm$
mod_gzip_item_include file \.php3$
mod_gzip_item_include file \.php$
mod_gzip_item_include file \.js$
mod_gzip_item_include file \.css$
mod_gzip_item_include mime ^text/
mod_gzip_item_exclude mime ^httpd/unix-directory
mod_gzip_item_exclude mime ^image/
mod_gzip_dechunk Yes
mod_gzip_add_header_count Yes
mod_gzip_send_vary Yes
</IfModule>
N'oubliez pas de recharger Apache après chaque modification de la configuration.
Les options sont relativement parlantes (pour les anglophones), elles ne seront pas détaillées dans cet article.
Microsoft IIS
IIS supporte la compression depuis la version 4, mais celle-ci est victime de bugs. Dans la version 5, les efforts de Microsoft n'ont pas porté leurs fruits puisque celle-ci est toujours instable. C'est enfin dans la version 6 que la compression HTTP a été finalisée. Cependant elle nécessite quelques manipulations (voir documentation Microsoft : Using HTTP Compression for Faster Downloads (IIS 6.0) et tutoriel en français pour activer la compression GZip dans IIS6.
Les autres serveurs restent marginaux. Lighttpd est équipé du module bien nommé mod_compress.
Solutions rapides avec un .htaccess pour Apache
Les fichiers .htaccess sont des fichiers placés à la base d'un répertoire et modifiant le comportement du serveur pour les fichiers qu'il contient. On peut y placer les instructions de configuration mentionnées ci-dessus (sans la directive Location ou Directory).
Voici des exemples testés et exploités sur Alsacreations.com. Si vous obtenez des erreurs HTTP 500 après la mise en place du fichier .htaccess, vérifiez sa syntaxe, l'adéquation avec votre type de serveur et la disponibilité des modules. Vous pouvez également combiner le tout avec des options de cache (mod_expires dans l'exemple pour Apache 1.3) pour éviter de servir plusieurs fois le même contenu aux visiteurs et sa compression par le serveur - ceci relève d'un autre article.
Apache 2
Contenu du fichier .htaccess, dans le répertoire contenant les fichiers CSS et JavaScript.
# Apache 2.0
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-javascript
Apache 1.3
# Compression pour fichiers CSS
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_minimum_file_size 1024
mod_gzip_maximum_file_size 100000
mod_gzip_item_include file \.css$
mod_gzip_item_include mime ^text/css$
</IfModule>
<IfModule mod_expires.c>
ExpiresActive on
ExpiresDefault "access plus 1 month"
ExpiresByType text/css "access plus 1 day"
ExpiresByType image/png "access plus 1 week"
ExpiresByType image/gif "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 week"
</IfModule>
# Compression pour fichiers JS
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_minimum_file_size 512
mod_gzip_maximum_file_size 1000000
mod_gzip_item_include file \.js$
mod_gzip_item_include mime ^application/x-javascript.*
</IfModule>
# Cache
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType application/x-javascript "access plus 2 month"
ExpiresByType application/javascript "access plus 2 month"
ExpiresByType text/javascript "access plus 2 month"
</IfModule>
Solution alternative en PHP
La fonction ob_gzhandler et l'ensemble des fonctions de type ob_* disponibles depuis PHP4 permettent la gestion du tampon de sortie, c'est à dire des données qui seront envoyées au navigateur. Il est alors possible de générer le contenu complet de la page et de le compresser avec Gzip avant envoi. On active le tampon en début de script avec ob_start, et on le vide à la fin avec ob_end_flush.
La fonction ob_gzhandler a le mérite de vérifier les types de compressions supportés par le navigateur (gzip, deflate ou aucun) avant de retourner le contenu du tampon de manière appropriée. Si le navigateur ne supporte pas les pages compressées, cette fonction retournera false.
<?php
ob_start("ob_gzhandler");
?>
... Le reste du code ...
<?php
ob_end_flush();
?>
Bien sûr, ceci est à adapter en fonction de la structure de votre site. Il ne suffit pas toujours de placer ces instructions en début et en fin de script PHP car de nombreux CMS utilisent déjà leur propre système de buffer (tampon) interne.
Tests dans la pratique
Vous pourrez aisément vérifier le bon déroulement du transfert et de la décompression en vérifiant les propriétés de la page dans le navigateur (dans Firefox : clic bouton droit, Informations sur la page, onglet Général, Taille). Comparez la taille du fichier original et la taille lue (à l'octet près).

Consultez également les indications fournies par les extensions de développement (type Firebug ou Outils de développement accessibles dans les navigateurs modernes). Celles-ci figurent dans l'onglet Réseau ou Network, et mentionnent les en-têtes HTTP de compression ainsi que la quantité de données téléchargées.




arnolem a dit le
En ce qui concerne la solution PHP, je ne suis pas sûr que le ob_end_flush(); soit nécessaire