Votre site est en ligne et vous avez tout fait pour optimiser son contenu. En êtes-vous absolument certain ? Avez-vous aussi optimisé le comportement de votre serveur ?
Dans cet article, nous abordons l'optimisation du traffic, côté serveur.
Aujourd'hui, plus de 60% des sites sont hébergés sur des serveurs Apaches (Usage statistics and market share of Apache for websites).
Dans cet artcile, nous allons voir comment optimiser le comportement du serveur avec des techniques utilisables méme dans le cas d'un hébergement pour lequel vous n'accédez pas à la confirguration intime d'Apache.
Le fichier .htaccess
est un fichier de configuration permettant de définir le comportement d'Apache pour le répertoire (et ses sous-répertoires) dans lequel il doit agir.
Il est donc tout à fait possible de mettre en place différentes stratégies dans un même site en plaçant plusieurs fichiers .htaccess
à différents endroits, le fichier .htacess
parent restant actif tant que les directives qu'il contient ne sont pas modifiées.
Pour notre travail d'optimisation, nous allons donc travailler sur le fichier .htaccess
placé à la racine du site, car nous cherchons à améliorer le comportement pour l'ensemble du site.
Le fichier .htaccess est un simple fichier texte que vous pouvez éditer avec n'importe quel outil.
Note : Windows à du mal à travailler avec un fichier ne comportant qu'une extension. je vous suggère donc d'utiliser un éditeur texte un peu évolué ou de renommer, le temps de l'édition, le fichier en htaccess.txt
, par exemple.
Le fichier .htaccess
prend effet immédiatement, car il est lu à chaque requête sur votre serveur.
Cela signifie qu'une erreur de syntaxe ou de codage provoquera immédiatement un dysfonctionnement de votre site.
Par ailleurs, ce fichier permet des réglages fins et très puissants, alors ne le manipulez pas à la légère !
Enfin, il est à noter qu'une ligne débutant par #
est considérée comme commentaire.
Vous pouvez faire des essais avec l'exemple ci-dessous (en prenant garde de ne pas écraser un fichier .htaccess déjà présent !), en commentant / décommentant les directives d'accès au contenu de votre site.
#
# Cette directive n'est pas prises en compte :
# interdiction d'accès absolue au contenu
# -------------------------------------------------------
# deny from all
#
# Alors que celle-ci est appliquée :
# autorisation de tous les accès
# -------------------------------------------------------
allow from all
Comme évoqué plus haut, le fichier htaccess.txt
est lu lors de chaque accès au site.
En conséquence, limitez son contenu (donc sa taille) au minimu possible :
Pour exemple, le fichier htaccess.txt
de 1 Ko ci-dessous :
#
# Controles de comportement du site : www.monsite.com
# - auteur : I. Ahounou
# - modification : 1er novembre 2012
# =======================================================
#
#
# Types MIME
# -------------------------------------------------------
AddType text/html .htm
AddType text/html .html
AddType application/x-httpd-php .foo
AddType text/javascript .js
AddType text/css .css
AddType application/x-shockwave-flash .swf
AddType video/x-flv .flv
AddType image/gif .gif
AddType image/jpg .jpg
AddType image/png .png
AddType application/pdf .pdf
AddType application/zip .zip
#
# Accès universel
# -------------------------------------------------------
allow from all
#
# Langue par défaut et charset
# -------------------------------------------------------
AddDefaultCharset UTF-8
AddLanguage fr-FR .html .htm .css .js
#
# -------------------------------------------------------
# Fin du fichier .htaccess
# -------------------------------------------------------
#
Nous remarquons de nombreuses choses inutiles :
Il ne reste donc que l'application générique de la langue et du charset, qui sont une alternative viable si vous ne les décrivez pas dans le <header> des pages.
Il est donc possible, et recommandé, de transformer ce fichier, par exemple comme suit.
# I. Ahounou - 01/11/2012
# Langue par défaut et charset
AddDefaultCharset UTF-8
AddLanguage fr-FR .html .htm .css .js
Le fichier ne pèse plus que 128 octets et uniquement 2 directives sont prises en compte, sans altérer le comportement du serveur !
Apache est capable de transmettre des fichiers compressés au navigateur client qui se charge alors de les décompresser.
En activant cette possibilité, les fichiers transmis sont allégés de manière souvent drastique et transitent donc plus rapidement vers l'internaute.
Vous me direz que la contrepartie est du temps de décompression. Vous avez raison. Mais au regard de la puissance des machines actuelles, le gain de temps reste largement appréciable.
Pour utiliser cette possibilité, votre serveur s'appuie sur le module MOD_DEFLATE
que nous allons employer, uniquement s'il est opérationnel, avec la directive <IfModule module>...</IfModule>
.
Suivant le serveur exécutant Apache, ce module est soit mod_deflate.c
pour des environnements Unix, Linux, soit mod_deflate.so
pour des environnements Windows. Le code ci-dessous propose les 2 tests de présence en utilisant uniquement l'identificateur.
Pour être véritablement efficace, il est important de préciser aux différents proxy intermédiaires de la chaîne de transmission Internet de ne pas décompresser le contenu à la place de l'internaute. Ceci est possible en ajoutant une directive de type header
lors de l'utilisation de la compression serveur.
Mais bien entendu, il existe des incompatibilités avec certains navigateurs, comme Netscape et Internet Explorer (pour les anciennes versions).
Nous pouvons traiter ces cas par des tests avec la directive BrowserMatch test
.
<IfModule mod_deflate>
# Compression avec MOD_DEFLATE
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml text/javascript application/x-javascript application/x-httpd-php
#Pour les navigateurs incompatibles
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Les proxies ne doivent pas décompresser à la place de l'internaute
Header append Vary User-Agent env=!dont-vary
</IfModule>
En contrôlant l'activité du cache du navigateur client, il est possible de le forcer à enregistrer une copie locale des fichiers statiques (images, fichiers html, etc.), mais en conservant hors cache les fichiers dynamiques (php et cgi).
En réalisant cette opération, une partie non négligeable des fichiers ne transitent plus par Internet, mais sont directement lus depuis le disque dur de l'ordinateur. Gain de temps maximal pour l'affichage des pages, du moins pour les visiteurs réguliers !
Pour contrôler les fichiers mis en cache, nous allons utiliser la directive <FilesMatch test>...</FilesMatch>
, pour manipuler le header
.
Note : La syntaxe des tests utilisés par la directive FilesMatch
s'appuie sur les expressions régulières. Vous pouvez vous familiariser, si nécessaire avec cette syntaxe, en utilisant les tutoriaux du site Expreg.com/ et réaliser des test préliminaires depuis le site Annuaire-Info.com.
<IfModule mod_headers>
# Mise en cache pour un mois
<FilesMatch ".(ico|jpe?g|png|gif|swf|flv|gz)$">
Header set Cache-Control "max-age=2592000"
</FilesMatch>
# Mise en cache pour 2 heures
<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=7200"
</filesMatch>
# Désactive la mise en cache
<FilesMatch ".(pl|php|cgi)$">
Header unset Cache-Control
</FilesMatch>
</IfModule>
Dans la même logique que la gestion du cache, il est possible de préciser au serveur que des fichiers suffisament récent sont déjà en possession de l'utilisateur et qu'il n'est pas utile de les transmettre une nouvelle.
Pour cela, il faut utiliser les directives Expires... du module mod_expires.
Par exemple :
<IfModule mod_expires>
ExpiresActive On
ExpiresDefault "access plus 7200 seconds"
AddType image/x-icon .ico
ExpiresByType image/gif "access plus 2592000 seconds"
ExpiresByType image/ico "access plus 2592000 seconds"
ExpiresByType image/jpg "access plus 2592000 seconds"
ExpiresByType image/png "access plus 2592000 seconds"
ExpiresByType image/jpeg "access plus 2592000 seconds"
ExpiresByType image/icon "access plus 2592000 seconds"
ExpiresByType image/x-icon "access plus 2592000 seconds"
ExpiresByType text/css "access plus 2592000 seconds"
ExpiresByType text/html "access plus 7200 seconds"
ExpiresByType text/javascript "access plus 2592000 seconds"
ExpiresByType application/xhtml+xml "access plus 7200 seconds"
ExpiresByType application/x-javascript "access plus 2592000 seconds"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
</IfModule>
A priori, la gestion du délai d'expiration n'est pas utile dans le cas de l'usage de la mise en cache et réciproquement. Choisissez l'une des deux méthode et allégez votre fichier .htaccess
!
Le ETAG permet d'identifier la version d'un fichier. Ainsi, en l'utilisant, le serveur sait s'il y a eu une mofidification du fichier depuis la précédente requête et peut donc décider, opportunément, de le transmettre.
L'inconvénient de cette gestion, est que le serveur et le client doivent s'informer mutuellement pour chaque fichier, ce qui consomme de la bande passante et du délai de réactivité.
Ma recommandation est donc de désactiver cette fonctionnalité.
Header unset ETag
FileETag none
En conclusion, vous trouverez ci-dessous la synthèse des paramétrages évoqués.
# Compression
<IfModule mod_deflate>
# Compression avec MOD_DEFLATE
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml text/javascript application/x-javascript application/x-httpd-php
#Pour les navigateurs incompatibles
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
# Les proxies ne doivent pas décompresser à la place de l'internaute
Header append Vary User-Agent env=!dont-vary
</IfModule>
# Cache
<IfModule mod_headers>
# Mise en cache pour un mois
<FilesMatch ".(ico|jpe?g|png|gif|swf|flv|gz)$">
Header set Cache-Control "max-age=2592000"
</FilesMatch>
# Mise en cache pour 2 heures
<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=7200"
</filesMatch>
# Désactive la mise en cache
<FilesMatch ".(pl|php|cgi)$">
Header unset Cache-Control
</FilesMatch>
</IfModule>
# Expiration
<IfModule mod_expires>
ExpiresActive On
ExpiresDefault "access plus 7200 seconds"
AddType image/x-icon .ico
ExpiresByType image/gif "access plus 2592000 seconds"
ExpiresByType image/ico "access plus 2592000 seconds"
ExpiresByType image/jpg "access plus 2592000 seconds"
ExpiresByType image/png "access plus 2592000 seconds"
ExpiresByType image/jpeg "access plus 2592000 seconds"
ExpiresByType image/icon "access plus 2592000 seconds"
ExpiresByType image/x-icon "access plus 2592000 seconds"
ExpiresByType text/css "access plus 2592000 seconds"
ExpiresByType text/html "access plus 7200 seconds"
ExpiresByType text/javascript "access plus 2592000 seconds"
ExpiresByType application/xhtml+xml "access plus 7200 seconds"
ExpiresByType application/x-javascript "access plus 2592000 seconds"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
</IfModule>
# Désactivation ETAG
Header unset ETag
FileETag none
Après essai, voici les résultats mesurés :
Page d'accueil | Images optimisées | |
---|---|---|
Premier accès, cache vide | ||
Sans optimisation .htaccess |
6,09 s | 7,27 s |
Avec optimisation .htaccess |
3,95 s | 3,71 s |
Gains | 2,14 s (= 35%) | 3,56 s (= 49%) |
Nouvel accès | ||
Sans optimisation | 4,35 s | 3,65 s |
Avec optimisation | 2,23 s | 1,9 s |
Gains | 2,12 s (= 49%) | 1,75 s (= 48%) |
Le constat est sans appel : en moyenne 45% de temps de chargement gagné pour chaque page.
Maintenant, c'est à vous, car n'oublions pas qu'il est communément admis qu'à chaque seconde de chargement d'une page, c'est 10 internautes qui fuient !