redirect to default language except for /amp/ Urls

2019-03-03 04:01发布

问题:

good day everyone, I'm struggling to solve a redirection but without any success. I changed the URLs of my site forcing a default language, before it was site.com/help/ and now it's site.com/en/help/ Thanks to anubhava I made the redirection, but then i faced a new problem with the AMP pages: site.com/amp/help/ are now redirected to site.com/en/amp/help/ while they are supposed to be site.com/amp/en/help/.

Again, thanks to Anubhava, I changed the structure of URLs to site.com/en/help/amp/ (amp always at the end). To achieve this, I had to delete the .php extention I had in some pages and also decided to remove the trailing slash.

I'm now facing 2 new issues: the 301 redirection to a non .php page and URLs with trailing slashes to a non trailing slash don't work :( bellow is my htaccess code

RewriteEngine on

# amp
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp [R=301,NC,L]

## redirect to default language (fr)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/inc
RewriteCond %{REQUEST_URI} !/ajax/
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /fr/$1 [R=301,L,NE]

## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]

## add trailing slash in front of directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+)$ /$1/ [L]

# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteCond %{REQUEST_URI} !/ajax/
RewriteCond %{REQUEST_URI} !results.php
RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L]

## amp pages
RewriteRule ^(.*)/amp$ /$1?amp=1 [NC,QSA,L]

## folders of languages
#RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]
RewriteRule ^([a-z]{2}|[a-z]{2}-[a-z]{2})$ /$2?lang=$1 [QSA,L]
RewriteRule ^([a-z]{2}|[a-z]{2}-[a-z]{2})/(.*)$ /$2?lang=$1 [QSA,L]

## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]

回答1:

Have it this way:

RewriteEngine on

# changed amp URLs
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp/ [R=301,NC,L]

## redirect to default language (en)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /en/$1 [R=301,L,NE]

## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !/amp/$ [NC]
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]

## add trailing slash in front of directories after lang rewrite
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+[^/])$ /$0/ [L]

# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^(.+)\.php$ /$1/ [R=301,NC,NE,L]

## amp pages
RewriteRule ^(.+/)amp/?$ /$1?amp=1 [NC,QSA,L]

## folders of languages
RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]

## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]

Explanation of this trailing slash rule:

## add trailing slash in front of directories after lang rewrite
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+[^/])$ /$0/ [L]

Take an example URI: /fr/cart.

In a later rule we remove lang component from URL and pass it as lang=<fr|en> query parameter. Part after lang parameter e.g. /cart doesn't have a trailing slash and if it is a real directory then /cart?lang=fr will be redirected to /cart/?lang=fr by Apache's mod_dir module and your internal URL will be exposed in browser.

So in this current rule we capture part after lang component and check if we don't have a trailing slash and it is a directory then this rule internally rewrites to /fr/cart/ with a trailing slash. Later rule then rewrites it to /cart/?lang=fr and mod_dir doesn't redirect anymore.



回答2:

as usual, thank you very much @anubhava for your time and precious help, I swear i would buy you a beer to thank you if we were in the same city :)

Your solution works perfectly well except for one little case: /fr/amp/page.php redirects to /fr/page.php/amp, i had to make some changed to your code and managed to make it work. Bellow is your updated code with small changes i made:

1- removed some slashes at the end of some rules as i don't need them anymore

2- removed this rule RewriteCond %{REQUEST_URI} !/amp/$ [NC]

3- I absolutely didn't understand what "add trailing slash in front of directories" is for, would you mind explaining it to me please?

4- I have noticed that you replaced (?![a-z]{2}/|[a-z]{2}-[a-z]{2}/)(.*)$ by (?![a-z]{2}(?:[/-]|$))(.*), what's the difference? just to be more clear and accurate, the folder of languages can be something like site.com/be-fr (french for belgium)

5- same for ([a-z]{2}|[a-z]{2}-[a-z]{2}) that has been replaced by ([a-z]{2}(?:-[a-z]{2})?) i'll need to capture the whole string (be-fr), so should I use ([a-z]{2}(-[a-z]{2})?)/(.*) or simply back to ([a-z]{2}|[a-z]{2}-[a-z]{2})

6- to fix the .php problem, i replaced RewriteRule ^(.+)\.php$ /$1/ [R=301,NC,NE,L] by RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L] is that okay?

7- just realized a second problem that i didn't manage to fix, it comes from ## folders of languages. site.com/fr returns a 404, it's because probably because of the slash in the rule :/

RewriteEngine on

## changed amp URLs
RewriteRule ^(.*/)?amp/(.+?)/?$ /$1$2/amp [R=301,NC,L]

## redirect to default language (en)
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_URI} !/img/
RewriteRule ^(?![a-z]{2}(?:[/-]|$))(.*)$ /en/$1 [R=301,L,NE]

## Unless directory, remove trailing slash
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/$ /$1 [R=301,NE,L]

## add trailing slash in front of directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^[a-z]{2}(?:-[a-z]{2})?/(.+)$ /$1/ [L]

# remove .php
RewriteCond %{ENV:REDIRECT_STATUS} !200
RewriteRule ^(.+)\.php(.*)$ /$1$2 [R=301,NC,NE,L]

## amp pages
RewriteRule ^(.+/)amp$ /$1?amp=1 [NC,QSA,L]

## folders of languages
RewriteRule ^([a-z]{2}(?:-[a-z]{2})?)/(.*)$ /$2?lang=$1 [QSA,L]

## hide .php extention
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_FILENAME} !global.js
RewriteRule ^(.+?)/?$ $1.php [L]