web-dev-qa-db-fra.com

Supprimer l'extension de l'URL à l'aide d'une réécriture sans entraîner de boucle de redirection

Sur le serveur, j'ai un fichier (sur le système de fichiers) appelé page.html, auquel je souhaite accéder en tant que site.com/page Ainsi, si quelqu'un accède à site.com/page.html, il doit 301 redirection vers site.com/page

J'ai vu des règles de réécriture qui gèrent la réécriture /page -> /page.html en interne, mais le forcer à 301 rediriger /page.html -> /page provoque également un boucle de redirection pour moi.

Le drapeau END semble pouvoir être utilisé pour faire ce que je veux, mais il n'est pas encore pris en charge.

J'ai aussi essayé d'utiliser ENV comme suit:

RewriteRule ^page$ /page.html [L,E=END:1]
RewriteCond %{ENV:END} !1
RewriteRule ^page.html$ /page [R=301,L]

Mais cela entraîne également une boucle de redirection.

4
arcyqwerty

J'ai demandé ceci même question sur StackOverflow . Pour que cela fonctionne correctement, vous devez utiliser des variables d'environnement:

RewriteRule ^page$ /page.html [L,E=LOOP:1]
RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^page.html$ /page [R=301,L]

En effet, mod_rewrite effectue plusieurs passages dans vos règles. Lors du premier passage, il définit la variable d'environnement. Au cours de la deuxième passe, la variable est précédée du préfixe REDIRECT_. Vous devez donc la lire sous la forme REDIRECT_LOOP.

3
Stephen Ostermiller

Le problème est que, lorsque vous utilisez mod_rewrite dans un fichier .htaccess ou une section <Directory>, chaque RewriteRule réussi - même interne - provoque le redémarrage de la demande en interne , et donc la totalité de la réécriture. jeu de règles à retraiter.

Ainsi, ce qui se passe, c'est que, lorsque l'utilisateur visite /page, votre RewriteRule interne correspond et réécrit l'URL sous /page.html. Mais cela fait que Apache redémarre le traitement de la requête et réexécute votre jeu de règles, ce qui provoque la correspondance de la règle external et réécrit et déclenche une redirection 301 vers /page.

Une solution rapide et délicate (mais efficace!) Consiste à obliger votre règle de réécriture interne à ajouter un paramètre factice tel que redirect=no à l'URL, puis à rechercher ce paramètre dans la règle de réécriture externe. Voici un exemple basé sur cette réponse que j'ai écrite pour une question similaire sur Stack Overflow :

RewriteEngine On
RewriteBase /

# Externally rewrite page.html -> page, unless query includes redirect=no:
RewriteCond %{QUERY_STRING} !(^|&)redirect=no(&|$) 
RewriteRule ^(page)\.html$ /$1  [NS,R=301,L] 

# Internally rewrite page -> page.html, add redirect=no to query:
RewriteRule ^(page)$ $1.html?redirect=no [NS,QSA]

(Bien sûr, n'hésitez pas à remplacer redirect=no par quelque chose d'autre si cela entre en conflit avec un paramètre d'URL que vous pourriez utiliser.)

3
Ilmari Karonen

Un moyen courant d’empêcher la boucle de redirection consiste à vérifier la variable de serveur THE_REQUEST, qui contient l’en-tête de la demande initiale, plutôt que le chemin d’URL de l’URL réécrite (dont le RewriteRulemodèle correspond à), qui est naturellement mis à jour lorsque l'URL est réécrite.

THE_REQUEST la valeur ne change pas car l'URL est réécrite en interne, et contient une chaîne de la forme suivante:

GET /page.html HTTP/1.1

Donc, cela pourrait être réécrit comme:

# Redirect direct requests for /page.html to the canonical URL
RewriteCond %{THE_REQUEST} \.html
RewriteRule ^(page)\.html$ /$1 [R=301,L]

# Rewrite the "pretty" URL to the actual filesystem path
RewriteRule ^(page)$ $1.html [L]

Dans ce cas, la condition THE_REQUEST s'assure simplement que .html est présent dans l'URL initialement demandée. La vérification de page.html est laissée à la RewriteRulemotif - qui est plus efficace (car elle est vérifiée en premier).

Il est toujours préférable d'avoir des redirections externes avant les réécritures internes.

0
MrWhite