Apprendre .htaccess : URL Rewriting
Le fichier .htaccess permet de réécrire des URLs dans le but de les simplifier et les rendre « SEO friendly ».
Qu’est-ce que l’URL rewriting ?
La réécriture d’URL (ou URL rewriting) est un moyen très efficace d’effectuer des redirections avancées ou simplement de changer l’apparence des URLs.
Les redirections et modifications d’URL sont des points qu’il est important de considérer pour le SEO d’un site web.
Activer le moteur de réécriture
Si le module mod_rewrite
est bien activé sur votre serveur, vous pourrez ensuite l’exploiter dans votre fichier 📄 .htaccess
en écrivant la directive suivante :
# Activation du module de réécriture
RewriteEngine on
Bases de l’URL rewriting
Règles de réécriture
Une fois le module de réécriture activé depuis notre 📄 .htaccess
, il est possible de définir des règles de réécriture.
Une règle de réécriture se déclare avec la directive suivante :
RewriteRule <modèle> <substitution> [<drapeaux>]
Les 3 arguments, séparés par des espaces ont un rôle bien distinct :
modèle
: le modèle des URLs pour lesquelles la règle doit s’appliquer.
Ce pattern s’écrit sous forme d’expression régulière s’appliquant sur le chemin de l’URL (la partie après le nom de domaine et avant le ?
des paramètres d’URL GET
)
substitution
: en quoi la requête correspondante doit être transformée. Il peut s’agir :
- D’un chemin (vers un fichier ou correspondant à une route de l’application)
- D’une URL absolue (avec
http://
ouhttps://
) - D’un tiret (noté
-
) indiquant qu’aucune substitution ne doit être effectuée. Ceci est utile quand un drapeau doit être appliqué sans modifier le chemin.
[drapeaux]
ou « flags » (optionnel) : options affectant la requête réécrite. Consulter la liste des drapeaux.
RewriteRule ^demo$ demo.php [NC]
- Le symbole
^
signifie le début de l’URL, après le nom de domaine (« rien avant »). - Le symbole
$
signifie la fin de l’URL (« rien après »). demo
est le modèle d’URL pour lequel la règle doit s’appliquer.demo.php
est le fichier de substitution associé au modèle.[NC]
est le drapeau qui spécifie que la règle n’est pas sensible à la casse.
Le fait d’accéder à http://monsite.com/demo
dans le navigateur va pointer vers le fichier demo.php
(sans que l’on s’en aperçoive - l’URL ne changera pas). Les 3 URLs suivantes seront alors valides :
http://monsite.com/demo
: car il s’agit de la règle définie.http://monsite.com/Demo
: car la règle n’est pas sensible à la casse.http://monsite.com/demo.php
: car le fichier d’origine répondra toujours à la requête normalement.
Conditions de réécriture
Il est possible de spécifier une ou plusieurs condition(s) préalable(s) à l’exécution d’une RewriteRule
. Ces conditions sont particulièrement utiles si l’on ne souhaite pas conditionner notre règle de redirection au modèle d’URL seul (comme c’est le cas avec RewriteRule
). Cela se fait alors par l’intermédiaire de la directive RewriteCond
.
Une condition de réécriture se déclare avec la directive suivante :
RewriteCond <caracteristique> <condition> [<drapeaux>]
Les 3 arguments, séparés par des espaces ont un rôle bien distinct :
caracteristique
: une variable serveur (à la forme%{VARIABLE}
) décrivant une caractéristique de la requête.condition
: une condition sous forme d’expression rationnelle correspondant à la variable serveur.[drapeaux]
ou « flags » (optionnel) : options affectant la requête réécrite. Consulter la liste des drapeaux.
RewriteCond %{HTTP_HOST} !https://monsite.com$
RewriteRule ...
Cet exemple déclenchera la RewriteRule
qui suivra uniquement si l’URL de la requête est différente de https://monsite.com
.
Références arrières
Comme on utilise des expressions régulières avec RewriteRule
et RewriteCond
, on va pouvoir capturer des portions de chaînes pour les réutiliser. Cela se fait via l’usage de parenthèses capturantes ()
autour de notre expression régulière.
Considérons l’extrait htaccess suivant :
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)$
RewriteRule ^(.*) http://%2/laconsole/htaccess/test/$1?subdomain=%1 [R=301,L,NE]
Ici les parenthèses permettent de capturer l’expression régulière .*
et de les placer dans une variable (invisible) à laquelle on pourra faire référence depuis la chaîne de subsitution
d’une règle de réécriture. Dans une expression régulière :
- Un point
.
représente un caractère quelconque, sauf pour un saut de ligne - Une astérisque
*
signifie « zéro ou plusieurs occurrences »
Cette expression régulière indique donc « une suite de 0 ou plusieurs caractères quelconques ».
Les références arrières de règle $N
Pour N
compris entre 1≤N≤9, elles font référence aux parenthèses capturantes du modèle
de la rewriteRule
.
Les références arrières de condition %N
Pour N
compris entre 1≤N≤9, elles font référence aux parenthèses capturantes de la condition
de la rewriteCond
.
Considérons le 📄 .htaccess
suivant :
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)$
RewriteRule ^(.*) http://%2/path/to/project/$1?subdomain=%1 [R=301,L,NE]
Ce fichier htaccess va réécrire une URL de la forme http://blog.localhost/foo/bar
en http://localhost/foo/bar/?subdomain=blog
%1
récupère les caractères avant le point.
dans le%{HTTP_HOST}
(ici :blog
)%2
récupère les caractères après le point.
dans le%{HTTP_HOST}
(ici :localhost
)$1
récupère le chemin d’URL depuis la racine du projet (ici :foo/bar/
)
Préfixe d’URL
Dans le cas où la requête initiale, ainsi que la substitution
(définie dans la RewriteRule
), ne se situent pas par rapport au répertoire racine du serveur (DocumentRoot
), il est bien souvent important (mais pas systématique - voir documentation) de déclarer un préfixe d’URL grâce à la directive suivante :
RewriteBase <chemin_racine>
Cette directive permet de spécifier le préfixe d’URL à utiliser pour les RewriteRule
qui réécrivent vers un chemin relatif.
Considérons l’architecture de dossiers suivante :
📁 www
| 📁 site1
| | ...
| 📁 site2
| 📁 site3
On pointera ainsi vers site 1 avec la directive RewriteBase /site1/public
.
Quelques grandes règles de réécriture
Exploitons ici la mécanique de l’URL rewriting pour gérer 3 grands classiques : la redirection HTTP vers HTTPS, la redirection WWW vers le domaine de base ou encore la réécriture des « query strings ».
1. Redirection HTTP vers HTTPS
Il est aujourd’hui primordial pour un site web d’être consulté via le protocole HTTPS
. C’est un gage de sécurité pour les utilisateurs (données cryptées) et un point non négligeable en termes de bénéfices SEO.
Lorsqu’un site possède un certificat SSL, il est apte à être consulté via le protocole HTTPS
. Pour éviter toute exploitation malencontreuse du protocole HTTP
, les développeurs ont alors pris l’habitude de rediriger les URLs HTTP
vers HTTPS
.
L’extrait suivant permet de rediriger les requêtes HTTP
vers HTTPS
:
# Rediriger HTTP vers HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
RewriteEngine On
permet d’activer le mode de réécriture.
Une règle de réécriture s’applique uniquement si les conditions spécifiées par RewriteCond
sont remplies.
RewriteCond %{HTTPS} !=on
signifie que la réécriture ne sera effective que si l’URL est demandée sans le protocole HTTPS. En fonction du serveur, il peut être possible de spécifier RewriteCond %{HTTPS} off
.
Une règle de réécriture est définie avec l’instruction RewriteRule
.
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
réécrit le protocole HTTP
vers HTTPS
, quelle que soit la ressource demandée sur le domaine en question.
%{HTTP_HOST}
fait référence au nom de domaine du site.%{REQUEST_URI}
fait référence au chemin vers la ressource demandée.
Certains drapeaux sont définis entre crochets :
L
garantit qu’aucune autre règle n’est appliquée à cette demande si cette règle est exécutée.R
précise le type de redirection à retourner au navigateur.NE
permet d’éviter de convertir les caractères spéciaux (comme#
,&
et?
) en leur équivalent hexadécimal (%23
…).
2. Redirection WWW vers le domaine de base
Historiquement, le sous-domaine www
(pour « World Wide Web ») était automatiquement attribué aux sites web (www.mondomaine.com
), qui n’étaient bien souvent accessibles que par ce dernier. Il n’était pas toujours possible d’y accéder via mondomaine.com
.
Aujourd’hui, si certains hébergeurs vont continuer à créer un sous-domaine en www
pour chaque site, son usage à tendance à disparaître. Cela se traduit généralement par la mise en place d’une redirection du domaine en www
vers le domaine initial, de sorte à ne pas rendre accessible 2 pages avec un contenu identique.
Pourquoi cela ? Car les moteurs de recherche n’apprécient pas le « duplicate content ».
Voici un extrait permettant de rediriger les domaines en www
vers le domaine de base :
# Rediriger www vers le domaine de base
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*) https://%1%{REQUEST_URI} [R=301,L,NE]
%{HTTP_HOST}
fait référence au nom de domaine du site.%{REQUEST_URI}
fait référence au chemin vers la ressource demandée.- Dans la condition de réécriture,
(.*)
capture le nom de domaine qui pourra être récupéré dans%1
. - Le drapeau
NC
rend la chaîne insensible à la casse.
3. Réécriture des « query strings »
Nous avons vu au chapitre précédent que la réécriture d’URL permettait d’effectuer des redirections plus complexes au sein d’un fichier 📄 .htaccess
.
Mais quand on parle d’URL rewriting, on pense plus généralement à la réécriture sans redirection, mais visant uniquement à en changer leur apparence.
Bien souvent, les URLs d’un site web dynamique contiennent des paramètres GET
. Cette portion variable est d’ailleurs aussi appelée « query strings ». Si ces paramètres présentent l’avantage indéniable de pouvoir faire varier le contenu d’un fichier en fonction de leur valeur, côté SEO, il vaut mieux ne pas avoir des attentes trop élevées…
Pourquoi cela ? Et bien car toutes les informations permettant de charger des pages différentes depuis notre fichier 📄 index.php
passent par des paramètres GET
. Nos URLs sont par conséquent longues, peu explicites et ne laissent pas transparaître de notion de « profondeur ».
Quelle URL préférez-vous ?
https://monsite.com/products.php?category=computer
https://monsite.com/products/computer
Ne dites pas la première, personne ne vous croira. 🙃
L’URL rewriting consistera donc à transformer une URL complexe (contenant généralement des paramètres GET
) en une URL plus simple pour l’internaute, mais surtout pour les moteurs de recherche. On parle aussi d’URL « SEO friendly ».
Ainsi, 2 URLs seront différentes, mais pointeront vers une même ressource sur le serveur.
La directive RewriteRule
est idéale pour modifier l’apparence de nos query strings.
# Réécrire les URLs contenant des paramètres de requête GET "category"
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^products/(.*)$ products.php?category=$1 [NC,QSA,L]
%{REQUEST_FILENAME}
est une variable Apache qui représente le chemin réel dans le système de fichiers sur le serveur.
!
est un symbole qui désigne la négation du filtre qui suit-f
précise qu’il s’agit d’un fichier (f
pour « file ») et!-f
l’inverse.-d
précise qu’il s’agit d’un répertoire (d
pour « directory ») et!-d
l’inverse.
Les deux conditions de réécriture %{REQUEST_FILENAME} !-f
et %{REQUEST_FILENAME} !-d
excluent ainsi les URL correspondants à un fichier réel ou à un répertoire / sous-répertoire existant sur le site. Cela permet ainsi de ne pas réécrire les chemins vers les ressources (CSS, JS…).
Pour qu’une règle de réécriture ne déclenche pas de redirection (changeant l’URL dans la barre d’adresse), il y a 2 règles à respecter :
- L’URL cible doit être écrite via un chemin relatif (pas de
http://
ouhttps://
provoquant une redirection) - La directive
RewriteRule
ne doit pas contenir de drapeauR=xxx
(provoquant également une redirection propre au code HTTP spécifié).
Dans cette RewriteRule
, l’URL source cible products.php?category=$1
est écrite via un chemin relatif depuis le répertoire où est situé le fichier 📄 .htaccess
et aucune redirection n’est explicitée par le drapeau R=xxx
. En conséquence, l’URL ne sera pas modifiée visuellement dans la barre d’adresse du navigateur.
Nos URLs seront donc converties avec des paramètres GET
, mais ces derniers seront invisibles !
Pour exemple, l’URL https://monsite.com/products/computer
sera transformée en https://monsite.com/products.php?category=computer
sans que l’on s’en aperçoive car la barre d’adresse restera inchangée.
- Le drapeau
QSA
permet de conserver une chaîne de requête existante (d’autres paramètres d’URLGET
) qui aurait par défaut été écrasée par la règle de réécriture. En savoir plus - Le drapeau
L
indique que si la règle de réécriture s’applique, aucune autre règle ne doit être traitée.