9 min de lectureTutoriels

Redirection 301 dans .htaccess : règles, ordre, chaînes de requête

Une redirection 301 dans .htaccess, c'est une ligne de mod_alias. Voici cette ligne, quand RewriteRule est le bon outil à la place, et pourquoi l'ordre l'emporte sur la position dans le fichier.

Marius Voß
DevRel · edge infra
Une redirection 301 htaccess représentée comme une ligne mod_alias à côté d'une règle mod_rewrite, avec l'ordre d'exécution entre les deux

Une redirection 301 dans .htaccess tient en une ligne :

Redirect 301 /old-page https://example.com/new-page

Enregistrez cela dans le fichier .htaccess à la racine de votre document et c'est actif immédiatement. Apache lit le fichier à chaque requête, donc il n'y a ni redémarrage ni déploiement. La directive vient de mod_alias, présent sur pratiquement toutes les installations Apache, et elle envoie un 301 Moved Permanently avec un en-tête Location. C'est tout le travail.

Presque tout ce qui tourne mal avec les redirections Apache arrive après ce point : recourir à RewriteRule quand Redirect suffirait, mélanger les deux modules dans un seul fichier et obtenir un ordre que personne n'attendait, ou perdre la chaîne de requête en chemin. Cet article couvre les quatre règles qui valent la peine d'être mémorisées, le piège de l'ordre d'exécution qui fait mal se comporter des fichiers qui semblent corrects, et comment tester une redirection sans que votre navigateur ne vous mente. Pour la vue d'ensemble de tous les endroits où une redirection peut vivre, voir comment rediriger une URL.

La ligne unique qui couvre la plupart des redirections

Redirect prend un statut, un chemin à faire correspondre, et une cible. La cible peut être une URL complète ou un chemin sur le même hôte :

Redirect 301 /old-page /new-page
Redirect 301 /shop https://shop.example.com/
RedirectMatch 301 ^/blog/([0-9]{4})/(.*)$ /articles/$2

Deux comportements valent la peine d'être connus avant de l'utiliser. D'abord, les directives officielles d'Apache sont explicites sur le fait que c'est le bon outil : "Ce type de redirection simple d'une URL, ou d'une classe d'URLs, vers un autre emplacement, devrait être accompli en utilisant ces directives plutôt que RewriteRule."

Ensuite, et celui-ci surprend les gens : "Rappelez-vous que Redirect préserve l'information de chemin. C'est-à-dire qu'une redirection pour une URL /one redirigera aussi toutes les URLs qui se trouvent sous elle, comme /one/two.html et /one/three/four.html." Si vous voulez seulement le chemin exact, RedirectMatch 301 ^/one$ l'ancre. Sinon, vous venez de rediriger une sous-arborescence entière, ce qui est parfois exactement ce que vous vouliez et parfois une matinée très déroutante.

RedirectMatch est la version regex, et elle couvre l'essentiel de ce pour quoi les gens ouvrent mod_rewrite. Les groupes capturés atterrissent dans $1, $2, et ainsi de suite, donc un renommage de répertoire ou un changement de schéma d'URL basé sur une date se règle en une seule ligne.

Quand vous avez réellement besoin de RewriteRule

Utilisez mod_rewrite quand la décision dépend d'autre chose que le chemin. L'hôte, la chaîne de requête, la méthode de requête, les cookies et l'agent utilisateur sont tous visibles pour RewriteCond et invisibles pour Redirect :

RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)ref=oldpartner(&|$)
RewriteRule ^landing$ /partners/oldpartner? [R=301,L]

Il y a un piège dans le contexte par répertoire qui explique une grande partie des règles copiées-collées qui ne font absolument rien. Apache retire le préfixe de répertoire avant la correspondance, donc le motif ne voit jamais de barre oblique de début : "Le préfixe retiré se termine toujours par une barre oblique, ce qui signifie que la correspondance s'effectue sur une chaîne qui n'a jamais de barre oblique de début. Par conséquent, un motif avec ^/ ne correspond jamais dans un contexte par répertoire."

C'est pourquoi RewriteRule ^/old$ /new [R=301] fonctionne quand quelqu'un le colle dans un virtual host, et échoue silencieusement dans .htaccess. Retirez la barre oblique : ^old$. Quand votre substitution est un chemin relatif et que la réécriture vit dans un sous-répertoire, vous pourriez aussi avoir besoin de RewriteBase pour indiquer à Apache par rapport à quoi les chemins sont relatifs.

Le piège de l'ordre d'exécution

C'est celui qui coûte une après-midi aux gens. La position de la ligne dans le fichier ne décide pas quel module s'exécute en premier.

Apache le documente clairement : "Si vous mélangez Redirect et RewriteRule dans le même contexte, sachez que leur ordre d'exécution dépend de l'endroit où ils apparaissent. Dans un contexte serveur/virtual-host, mod_rewrite s'exécute en premier ; dans un contexte par répertoire (.htaccess), mod_alias s'exécute en premier."

Lisez cela deux fois, parce que la conséquence est contre-intuitive. Dans un fichier .htaccess, un Redirect en bas de fichier l'emporte sur un RewriteRule en haut. Déplacez les règles identiques dans un virtual host et le gagnant s'inverse. Le drapeau [L] ne vous sauve pas non plus : il signifie dernière règle de cette passe de mod_rewrite, pas dernière règle du fichier, et il n'a aucune autorité sur un autre module.

La règle pratique que je suis : un module par fichier. Si un projet a besoin de conditions n'importe où, faites toutes ses redirections avec mod_rewrite et supprimez les lignes Redirect. Les fichiers mixtes sont d'où viennent les rapports de bugs du type "la redirection fonctionne en préproduction mais pas en production", parce que les deux environnements placent les règles dans des contextes différents.

Ordre d'exécution de mod_alias et mod_rewrite montrant que dans un fichier htaccess, mod_alias s'exécute en premier, quelle que soit la position dans le fichier

Chaînes de requête : conservées, remplacées ou effacées

Les liens marketing vivent et meurent par leurs chaînes de requête, donc ce tableau vaut la peine d'être épinglé. Tout cela est un comportement documenté plutôt qu'une légende.

Ce que vous écrivezChaîne de requête d'origineNotes
Redirect 301 /a /bTransféréemod_alias l'ajoute pour vous
RedirectMatch 301 ^/a$ /bTransféréeMême module, même comportement
RewriteRule ^a$ /b [R=301]Transmise sans changementLe comportement par défaut documenté
RewriteRule ^a$ /b?src=x [R=301]Remplacée par la vôtreVos paramètres l'emportent
RewriteRule ^a$ /b?src=x [R=301,QSA]Combinée avec la vôtreQSA ajoute l'originale
RewriteRule ^a$ /b? [R=301]EffacéeUn simple ? l'efface

La formulation d'Apache sur le comportement par défaut : "Par défaut, la chaîne de requête est transmise sans changement." Et sur les drapeaux, [QSA] "ajoute toute chaîne de requête de l'URL de requête d'origine à toute chaîne de requête créée dans la cible de réécriture", tandis que [QSD] rejette celle entrante. Si vous redirigez vers un URI absolu, la chaîne de requête suit à moins que vous ne demandiez [QSD].

L'échec que cela évite est silencieux et coûteux. Une règle qui remplace la chaîne de requête retire utm_source et utm_campaign au passage, votre outil d'analyse attribue la session au trafic direct, et rien ne produit d'erreur. Personne ne le remarque avant que quelqu'un ne demande pourquoi la campagne de printemps n'a reçu aucun crédit. Les paramètres UTM ne s'affichent pas dans GA4 couvre le diagnostic du côté analytique.

Si vous vous retrouvez à maintenir des dizaines de redirections de campagne dans un fichier de configuration serveur, c'est un signal plutôt qu'une corvée. Les règles serveur nécessitent un déploiement, une revue de configuration Apache, et quelqu'un ayant un accès shell. Déplacez les liens de campagne vers des liens courts que vous pouvez modifier vous-même et gardez .htaccess pour les redirections structurelles pour lesquelles il est bon.

HTTPS et www en un seul saut, pas deux

L'extrait le plus copié sur internet fait cela en deux blocs de règles, ce qui signifie qu'un visiteur arrivant sur http://example.com/page est redirigé deux fois : une fois pour ajouter TLS, une fois pour ajouter www. Deux sauts, deux allers-retours, et un signal légèrement plus faible à chaque fois.

Une règle, deux conditions, un saut :

RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

Derrière un CDN ou un répartiteur de charge, %{HTTPS} est généralement off à l'origine même quand le visiteur est en HTTPS, parce que le TLS s'est terminé en amont. Testez plutôt %{HTTP:X-Forwarded-Proto} :

RewriteCond %{HTTP:X-Forwarded-Proto} !https

Trompez-vous ici et vous construisez une boucle de redirection infinie : le proxy envoie du HTTPS, l'origine pense que c'est du HTTP, redirige vers HTTPS, et ça tourne en rond jusqu'à ce que le navigateur abandonne. Comment corriger une boucle de redirection détaille comment diagnostiquer cela à partir des en-têtes de réponse.

Deux règles htaccess séparées produisant une chaîne de redirection à deux sauts, comparées à une seule règle qui atteint l'URL canonique HTTPS www en un seul saut

Pourquoi ça ne fonctionne pas

Dans l'ordre où je les vérifie :

  1. AllowOverride est réglé sur None. La documentation d'Apache énonce le comportement par défaut : "Cela signifie que les fichiers .htaccess sont complètement ignorés sauf si vous les activez explicitement pour un répertoire." Testez cela en mettant délibérément du charabia sur la première ligne. L'absence d'erreur 500 signifie que votre fichier n'est pas lu du tout, et chaque règle qu'il contient n'est que de la décoration.
  2. Le fichier est mal placé ou mal nommé. Il doit s'appeler .htaccess, avec le point en début de nom, dans le répertoire vers lequel la requête pointe. Les éditeurs qui enregistrent utilement en htaccess.txt en sont une cause récurrente.
  3. mod_rewrite n'est pas chargé. Redirect fonctionne, RewriteRule échoue silencieusement, ce qui pousse les gens à examiner leur regex pendant une heure.
  4. Votre navigateur a mis en cache l'ancien 301. Chrome et Firefox mettent tous deux en cache les redirections permanentes de façon agressive, par profil de navigateur, donc le correctif que vous venez de déployer vous est invisible tout en fonctionnant parfaitement pour tout le monde d'autre. Pendant le développement, utilisez R=302 et passez à R=301 une fois la règle correcte.
  5. La règle correspond à sa propre cible. RewriteRule ^(.*)$ /index.php/$1 sans garde est le cas classique. Ajoutez une condition qui exempte la destination.

Testez avec curl, pas avec le navigateur

Une seule commande vous indique le statut, la cible, et le nombre de sauts effectués :

curl -sIL https://example.com/old-page | grep -iE '^HTTP|^location'

Lisez la sortie comme une séquence. Deux lignes HTTP/2 301 avant le 200 signifient deux sauts, et chaque saut est un vrai aller-retour pour un vrai visiteur sur un réseau mobile. La documentation de Google sur les redirections traite une redirection permanente comme le signal le plus fort pour consolider une URL, et y arriver en une étape est strictement mieux que d'y arriver en trois. Notre vérificateur de liens affiche la même chaîne dans un navigateur, et redirections 301 contre 302 couvre quel statut envoyer quand vous n'êtes pas sûr.

Testez les chemins qui comptent plutôt que celui que vous venez d'écrire : la racine, un chemin profond, un chemin avec une chaîne de requête, et la cible elle-même. Ce dernier test attrape les boucles avant vos visiteurs.

Quand ne pas utiliser .htaccess du tout

La position d'Apache est sans ambiguïté. "Si vous avez accès au fichier de configuration principal du serveur, vous devriez y placer toute votre configuration plutôt que dans des fichiers .htaccess," parce que l'analyse à chaque requête coûte un vrai travail : "autoriser les fichiers .htaccess entraîne une perte de performance, que vous les utilisiez réellement ou non." Sur un hébergement partagé, vous n'avez pas le choix. Sur un serveur que vous contrôlez, la configuration principale est le meilleur endroit pour tout ce qui est structurel.

Il existe une deuxième raison de garder les règles entièrement hors du fichier, et elle n'a rien à voir avec la performance. Les redirections qui apparaissent en impression, dans un code QR, ou sur le diaporama de quelqu'un d'autre doivent survivre à votre serveur web, à votre migration de CMS, et peut-être à votre hébergeur. Une règle dans .htaccess est à un déploiement négligent de disparaître, et personne ne signale un lien imprimé mort avant que la campagne ne soit terminée. Les redirections structurelles ont leur place sur le serveur ; les liens de campagne et d'impression ont leur place là où vous pouvez les modifier en quelques secondes et les mesurer sans fouiller dans les journaux d'accès.

Lisez la série pilier

Cet article s'inscrit dans le cluster de tutoriels. Pour la carte complète, types de redirections couvre chaque code de statut et chaque méthode côté client, et comment rediriger une URL couvre les six endroits où une redirection peut vivre.

Sur le blog

Questions fréquentes

Comment créer une redirection 301 dans .htaccess ?

Placez une seule ligne dans le fichier .htaccess à la racine de votre document : Redirect 301 /old-page https://example.com/new-page. Apache lit .htaccess à chaque requête, donc la redirection est active dès que vous enregistrez le fichier. Aucun redémarrage, aucun déploiement. Cette directive vient de mod_alias, activé sur pratiquement toutes les installations Apache.

Quelle est la différence entre Redirect et RewriteRule ?

Redirect et RedirectMatch viennent de mod_alias et font une seule chose : envoyer un code de statut et un en-tête Location. RewriteRule vient de mod_rewrite et peut examiner l'hôte, la chaîne de requête, les cookies, ou l'agent utilisateur avant de décider. La documentation officielle d'Apache dit qu'une redirection simple devrait utiliser mod_alias plutôt que RewriteRule, et traite mod_rewrite comme un dernier recours.

Pourquoi ma redirection .htaccess ne fonctionne-t-elle pas ?

Cinq causes couvrent presque tous les cas : AllowOverride est réglé sur None donc le fichier est entièrement ignoré, le fichier n'est pas à la racine du document ou est mal nommé, mod_rewrite n'est pas chargé, votre navigateur a mis en cache un 301 précédent et ne redemande jamais au serveur, ou la règle correspond à sa propre cible et boucle. Testez avec curl plutôt qu'avec un navigateur, car un 301 mis en cache fait paraître cassée une règle qui est en fait corrigée.

La chaîne de requête survit-elle à une redirection 301 dans .htaccess ?

Avec Redirect et RedirectMatch, oui, elle est transférée automatiquement. Avec RewriteRule, la réponse dépend de la substitution : sans point d'interrogation dedans, la chaîne de requête d'origine passe ; avec un point d'interrogation et vos propres paramètres, elle est remplacée ; un simple point d'interrogation à la fin l'efface ; et le drapeau QSA combine les deux. Se tromper ici fait disparaître silencieusement les paramètres UTM.

Comment rediriger HTTP vers HTTPS et non-www vers www en un seul saut ?

Utilisez une seule règle avec deux conditions jointes par OR, en réécrivant vers le schéma et l'hôte canoniques en une seule étape. Deux blocs de règles séparés produisent deux redirections pour quiconque arrive sur http:// sans www, et chaque saut supplémentaire coûte de la latence et dilue le signal. Derrière un proxy ou un CDN, testez %{HTTP:X-Forwarded-Proto} au lieu de %{HTTPS}, sinon vous construirez une boucle.

Est-ce que .htaccess ralentit un site ?

Légèrement, et inévitablement. La documentation d'Apache est directe à ce sujet : autoriser les fichiers .htaccess entraîne une perte de performance, qu'on les utilise ou non, parce que httpd recherche le fichier dans chaque répertoire à chaque requête. Si vous avez accès à la configuration principale du serveur, les mêmes règles ont plutôt leur place là, chargées une seule fois au démarrage.

Essayer Elido

Collez une URL, obtenez un lien court

Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.

Gratuit, sans inscription · 2 par jour

Essayer Elido

Raccourcisseur d'URL hébergé en UE : domaines personnalisés, analyses approfondies et API ouverte. Forfait gratuit - sans carte bancaire.

Tags
htaccess 301 redirect
apache redirect
mod_rewrite
301 redirect
redirect https
url redirect

Lire la suite