TUTORIEL - Eviter les boucles de redirection

WRInaute discret
Suite à la récurrence de ce problème dans bon nombre de sujets postés, voici un petit tutoriel pour vous éviter de chercher une solution miracle pendant des heures.

Contexte:
Votre site possède des urls identiques à fichier.php?arg1=val1&arg2=val&... (par exemple)
Vous en avez marre et décidez, pour une raison d'optimisation de référencement (ou pour une autre d'ailleurs...), de réécrire ces urls vraiment affreuses en des urls bien structurées et SEO-friendly.

But de la démarche:
Réécrire, par exemple
http://www.votresite.com/index.php?page=news&action=post
en
http://www.votresite.com/news/post
pour améliorer, notamment, le référencement.

Problématique:
S'il est aisé d'écrire une règle pour faire pointer l'url réécrite (la nouvelle) vers l'ancienne url, il faut néanmoins penser à interdire l'accès direct à l'ancienne url.

Ah bon? Et pourquoi?

Dans l'unique but d'éviter le fameux et tant détesté Duplicate Content !
En effet, si vous autorisez l'accès à un même contenu par plusieurs urls alors votre référencement risque d'en prendre un coup car Google n'aime pas ça.

Solution:
Reprenons l'exemple plus haut... On voudrait que l'url
http://www.votresite.com/news/post
pointe sur
index.php?page=news&action=post
sans oublier, bien entendu, d'interdire l'accès direct à
http://www.votresite.com/index.php?page=news&action=post

Vous seriez tenté d'écrire les règles suivantes:

Code:
RewriteEngine on

RewriteRule     ^(.*)/(.*)$       index.php?page=$1&action=$2 [L]

RewriteCond     %{QUERY_STRING}   ^page=(.*)&action=(.*)$
RewriteRule     ^index.php$       %1/%2? [R=301,L]

C'est en partie correct. Avec ce code, on obtient une belle boucle de redirection car l'un pointe sur l'autre qui lui même redirige vers le premier (vous voyez clairement la boucle se dessiner non? :))

Comment s'en sortir alors ?
L'astuce consiste à faire comprendre au serveur la différence entre une url réécrite par lui-même et une ancienne url accédée directement par l'utilisateur.

Code:
RewriteEngine on

RewriteRule     ^(.*)/(.*)$       index.php?page=$1&action=$2 [E=BREAK:1,L]

RewriteCond     %{ENV:REDIRECT_BREAK}     !^1$
RewriteCond     %{QUERY_STRING}   ^page=(.*)&action=(.*)$
RewriteRule     ^index.php$       %1/%2? [R=301,L]

Et voilà le travail ! Grâce à l'utilisation d'une variable d'environnement que l'on crée, le serveur sait maintenant faire la distinction entre les 2 cas !

Bien sur, cette solution peut s'adapter à toutes sortes de cas.
En espérant que ça aide pas mal de gens !
 
Nouveau WRInaute
Bonjour Giustino,
Un excellent Tutoriel, je vous remercie bcp car il m'a été d'une grande utilité, alors que je tournais en rond depuis quelques jours et mes redirections des anciens urls vers les nouvelles donnaient lieu à des boucles de redirection :)
Je propose au passage à Olivier de mettre à jour le tutoriel qu'il avait consacré au URL Rewriting accessible sur la page : https://www.webrankinfo.com/dossiers/techniques/tutoriel-url-rewriting
Si on y intègre l'astuce pour éviter les boucles de redirection, ça va être un excellent topic sur la réécriture d'urls et une référence en la matière sur le web.
J'ai toutefois un petit problème que je n'arrive toujours pas à résoudre (mais j'ai réussi quand même pas mal d'urls réécrites),
Je souhaite réécrire l'url d'une page contenant un paramètre (cid), mais cette fois-ci afin que chaque valeur de paramètre pointe vers une url précise qui ne contient pas ce paramètre sous une quelconque forme mais contient juste l'appellation que je lui définis.
La réécriture est réussie (enfin je le pense) car la page est accessible via la nouvelle url, mais la redirection ne marche pas.
Voici un exemple d'url et la façon avec laquelle j'avais tenté réussir la réécriture et la redirection :

RewriteRule ^banque-et-finance$ /modules/wfdownloads/viewcat.php?cid=1 [E=BREAK:1,L]
RewriteCond %{ENV:REDIRECT_BREAK} !^1$
RewriteRule ^modules/wfdownloads/viewcat.php?cid=1$ /banque-et-finance [R=301,L]


Je compte sur vos lumières pour réussir la redirection également et je vous remercie bcp pour votre soutien et disponibilité.
Mes salutations cordiales.
 
WRInaute discret
Bonjour Hafidov,

Ce tutoriel date d'il y a 2 ans, et bien que cette technique fonctionne toujours correctement, il y a en fait une manière moins "bricolage" d'y parvenir grâce à THE_REQUEST. Je ne peux malheureusement pas modifier mon tutoriel donc je vais le faire dans ce commentaire.

Pour reprendre mon exemple dans le tutoriel, le code serait désormais:
Code:
RewriteCond %{THE_REQUEST} \s/index\.php\?page=([^&\s]+)&action=([^&\s]+)\s [NC]
RewriteRule ^ /%1/%2? [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)/([^/]+)$ /index.php?page=$1&action=$2 [L]

Par rapport à votre problème, si j'ai bien compris selon votre code, vous désirez que l'url /banque-et-finance affiche le contenu de /modules/wfdownloads/viewcat.php?cid=1. Votre code est presque correct, mais la partie cid=1 fait partie de QUERY_STRING et n'est donc pas détectable directement dans RewriteRule. Voici la version corrigée:

Code:
RewriteRule ^banque-et-finance$ /modules/wfdownloads/viewcat.php?cid=1 [E=BREAK:1,L]

RewriteCond %{ENV:REDIRECT_BREAK} !^1$
RewriteCond %{QUERY_STRING} ^cid=1$ [NC]
RewriteRule ^modules/wfdownloads/viewcat\.php$ /banque-et-finance? [R=301,L]

Voici également, si vous le désirez, l'équivalent avec la nouvelle technique:

Code:
RewriteCond %{THE_REQUEST} \s/modules/wfdownloads/viewcat\.php\?cid=1\s [NC]
RewriteRule ^ /banque-et-finance? [R=301,L]

RewriteRule ^banque-et-finance$ /modules/wfdownloads/viewcat.php?cid=1 [L]
 
Nouveau WRInaute
Bonjour,

J'ai réussi à faire ça, avant de voir que le code était à jour plus bas…
Code:
RewriteRule     ^foo/([a-z0-9]+)/?$       foo.php?id=$1 [E=BREAK:1,L]
RewriteCond     %{ENV:REDIRECT_BREAK}     !^1$
RewriteCond     %{QUERY_STRING}   ^id=([a-z0-9]+)$
RewriteRule     ^foo.php$       foo/%1? [R=301,L]

Mais là je sèche pour la version sans break :

Code:
RewriteCond %{QUERY_STRING} ^id=([a-z0-9]+)$ [NC]
RewriteRule ^foo/%1/? [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^foo/([a-z0-9]+)/$ foo.php?id=$1 [L]

Une piste ?
 
WRInaute discret
Bonjour,

J'ai réussi à faire ça, avant de voir que le code était à jour plus bas…
Code:
RewriteRule     ^foo/([a-z0-9]+)/?$       foo.php?id=$1 [E=BREAK:1,L]
RewriteCond     %{ENV:REDIRECT_BREAK}     !^1$
RewriteCond     %{QUERY_STRING}   ^id=([a-z0-9]+)$
RewriteRule     ^foo.php$       foo/%1? [R=301,L]

Mais là je sèche pour la version sans break :

Code:
RewriteCond %{QUERY_STRING} ^id=([a-z0-9]+)$ [NC]
RewriteRule ^foo/%1/? [R=301,L]

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^foo/([a-z0-9]+)/$ foo.php?id=$1 [L]

Une piste ?

Voici la correction dans votre cas précis:

Code:
# Redirect /foo.php?id=XXX to /foo/XXX/
RewriteCond %{THE_REQUEST} \s/foo\.php\?id=([a-z0-9]+)\s [NC]
RewriteRule ^ /foo/%1/? [R=301,L]

# Internally rewrite /foo/XXX/ to /foo.php?id=XXX
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^foo/([a-z0-9]+)/$ /foo.php?id=$1 [L]
 
Nouveau WRInaute
Bonjour, je ne sais pas si j'aurais du créer un nouveau topic pour ma question, mais le titre de celui-ci correspond à mon questionnement : comment éviter des boucles de redirection ...

Car j'ai lu ci-et-là que si l'on créé des redirections 301 via htaccess depuis le même serveur vers le même serveur, ça va faire des boucles. A moins d'utiliser le mod-rewrite ce qui complexifie un peu l'écriture.

Mais je me demande si dans mon cas, ... ce serait le cas ! ?
Je m'explique :
- je suis sur le point de migrer un site, changement de domaine (truc.fr vers truc.com)
- et de serveur (dédié)
- nouvelle structure de site, nouvelles urls
- donc il change de serveur (nouvelle ip)
- je souhaite résilier cash l'ancien dédié
- rattacher l'ancien ndd truc.fr au nouveau serveur, en utilisant plesk, donc en déclarant un nouveau site (nouveau virtual host, donc pas le même que truc.com)
- et sur l'espace alloué pour truc.fr, juste mettre un htaccess avec des redirections 301 vers truc.com, donc dans un autre vhost, ...
Mais sur le même serveur, même @ip ... je me tors le cerveau peut-être pour rien, mais ne voulant pas faire de bêtise, c'est un site 'important', j'aurais voulu en être sûr ;)

Est-ce que quelqu'un pourrait me conseiller sur ce cas de figure ?

Merci beaucoup d'éclairer ma lanterne, et de vos conseils précieux !

Salutations,
 
WRInaute passionné
Je déterre ce vieux thread car je cherche une solution propre pour ré-écrire une url via une règle de ré-écriture dans mon fichier thaccess :

Je voudrais ré-écrire une vieille url du type http://mon-site.com/repertoire/index.php?rub=ma_page en https://www.mon-site.com/repertoire/ma-page.html quel serait le code à inclure dans mon fichier htaccess ?

Pour l'instant j'ai ça :
Code:
RewriteCond %{HTTP_HOST} !^www\.mon-site\.com [NC]
RewriteRule (.*) http://www.mon-site.com/$1 [QSA,R=301,L]
RewriteRule ^([a-zA-Z]*)/([a-zA-Z]*)-([a-zA-Z]*).html$ /$1/index.php?rub=$2_$3 [L]
La première condition permet de rediriger les urls sans les 3 www vers une url du type http avec les 3 www.

La deuxième règle permet de ré-écrire /repertoire/index.php?rub=ma_page en /repertoire/ma-page.html

Le problème c'est que j'ai une première redirection 301 des urls n'ayant pas les 3 www vers mon url en http et aujourd'hui mon site est en https donc il faudrait refaire une redirection de toutes les anciennes urls en http vers les https mais ça ferait alors 2 redirections 301, y a-t-il une solution pour faire tout cela avec 1 seule redirection ?

Autrement dit, comment je passe de http://mon-site.com/repertoire/index.php?rub=ma_page vers https://www.mon-site.com/repertoire/ma-page.html avec une seule redirection 301 ?

Merci pour vos réponses.
 
WRInaute passionné
J'ai essayé le code ci-dessous mais il y a plusieurs redirections 301 qui s'enchainent si l'url de départ est http//mon-site.com :
Code:
### Redirection 301 vers HTTPS et "www"
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^.*$ https://www.%1%{REQUEST_URI} [L,NE,R=301]
Première redirection 301 : http//mon-site.com vers http//www.mon-site.com
Deuxième redirection 301 : http//www.mon-site.com vers https//www.mon-site.com

Peut-on écrire une règle qui ré-écrit toutes les possibilités des urls (en http et www) avec une seule redirection 301 ?
 
Discussions similaires
Haut