admin管理员组

文章数量:1289362

I'm using my index.php file to handle all requests to my domain (except of course, css, js etc and files that actually exist). That works perfectly. What I want now is remove all trailing slashes so that mydomain/folder/file/ goes to mydomain/folder/file. I came across this solution

RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]

here: Htaccess: add/remove trailing slash from URL I see it as a very elegant solution, it actually works but here's is what I find strange:

  • On live domain it works perfectly
  • On localhost, localhost/mydomain/folder/file/ redirects fine, localhost/mydomain/folder/ too but localhost/mydomain/ simply says 'localhost redirected you too many times'. How do I get the redirect to work fine both on a live server and localhost? Or should I just fet about this and use htaccess only on the live server?

Here's the rest of my htaccess file. Pasting everything just incase one of the commands is affecting or overriding the other, I'm not a htaccess expert please. Thanks.

RewriteEngine On
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L] #added slash here too, don't fet it

RewriteCond %{SERVER_PORT} 80
RewriteCond %{HTTP_HOST} ^example\$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\$
RewriteRule ^(.*)$ /$1 [R=301,L]

RewriteCond %{HTTP_HOST} www.example
RewriteRule (.*) /$1 [R=301,L]

#RewriteRule ^(.*)index\.(php|html?)$ /$1 [R=301,NC,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

#Header set X-Frame-Options "ALLOW-FROM /"

Redirect 301 "/brand" "/brands"

ErrorDocument 404 /404.php
ErrorDocument 502 /502.shtml
ErrorDocument 504 /504.shtml
ErrorDocument 508 /508.shtml

<Files ~ "\.env$">  
Order Allow,Deny
Deny from All
</Files>

<Files .htaccess>
Order allow,deny
Deny from All
</Files>

Options -Indexes

<filesMatch ".(jpg|jpeg|png|gif|ico|webp|js)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>

<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=60, public"
</filesMatch>

I'm using my index.php file to handle all requests to my domain (except of course, css, js etc and files that actually exist). That works perfectly. What I want now is remove all trailing slashes so that mydomain/folder/file/ goes to mydomain/folder/file. I came across this solution

RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]

here: Htaccess: add/remove trailing slash from URL I see it as a very elegant solution, it actually works but here's is what I find strange:

  • On live domain it works perfectly
  • On localhost, localhost/mydomain/folder/file/ redirects fine, localhost/mydomain/folder/ too but localhost/mydomain/ simply says 'localhost redirected you too many times'. How do I get the redirect to work fine both on a live server and localhost? Or should I just fet about this and use htaccess only on the live server?

Here's the rest of my htaccess file. Pasting everything just incase one of the commands is affecting or overriding the other, I'm not a htaccess expert please. Thanks.

RewriteEngine On
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L] #added slash here too, don't fet it

RewriteCond %{SERVER_PORT} 80
RewriteCond %{HTTP_HOST} ^example\$ [OR]
RewriteCond %{HTTP_HOST} ^www\.example\$
RewriteRule ^(.*)$ https://example/$1 [R=301,L]

RewriteCond %{HTTP_HOST} www.example
RewriteRule (.*) https://example/$1 [R=301,L]

#RewriteRule ^(.*)index\.(php|html?)$ /$1 [R=301,NC,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

#Header set X-Frame-Options "ALLOW-FROM https://whatismyscreenresolution/"

Redirect 301 "/brand" "/brands"

ErrorDocument 404 /404.php
ErrorDocument 502 /502.shtml
ErrorDocument 504 /504.shtml
ErrorDocument 508 /508.shtml

<Files ~ "\.env$">  
Order Allow,Deny
Deny from All
</Files>

<Files .htaccess>
Order allow,deny
Deny from All
</Files>

Options -Indexes

<filesMatch ".(jpg|jpeg|png|gif|ico|webp|js)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>

<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=60, public"
</filesMatch>
Share Improve this question asked Feb 20 at 13:58 ChimdiChimdi 3793 silver badges9 bronze badges 6
  • 1 "Or should I just fet about this and use htaccess only on the live server?" - IMHO, you should fet about this, and not do it on the live system either. Why would files get requested with a trailing slash to begin with, are there links set anywhere with those "wrong" URLs? And why do you want to remove it when the path targets a folder in the first place? – C3roe Commented Feb 20 at 14:07
  • I'm guessing the problem on local is probably that you are accessing this via localhost/mydomain/, with an additional folder in the path. mod_dir's DirectorySlash is probably set to on, so it will try to redirect you from localhost/mydomain to localhost/mydomain/ again. – C3roe Commented Feb 20 at 14:09
  • @C3roe I'm using RewriteRule ^(.*)$ index.php?url=$1 [L,QSA] to map to my root index file, so basically I use 1 file to handle all url requests, the URLs (except css, js) are not existent files, just methods in classes, with the classes acting as directory and methods acting as files, so when someone types d/file/ or d/file in the url bar, it loads the same content (duplicate content) so I want 1 url version across all url requests. – Chimdi Commented Feb 20 at 21:45
  • 1 @Chimdi "when someone types d/file/ or d/file in the url bar, it loads the same content (duplicate content)" - that is something you should control in your PHP router. Your PHP code must be resolving both requests into one for both URLs to return the same response - perhaps you should not be doing that, then one will naturally result in a 404 (assuming that's what your router does). Or redirect one to the other in your PHP router/script - by doing this in PHP you can selectively redirect only the URLs that need redirecting and not URLs that would otherwise result in a 404 anyway. – MrWhite Commented Feb 21 at 0:14
  • 1 @Chimdi I've added the comment about handling this in the "PHP router" instead into by answer. – MrWhite Commented Feb 23 at 0:21
 |  Show 1 more comment

2 Answers 2

Reset to default 1

but localhost/mydomain/ simply says 'localhost redirected you too many times'. How do I get the redirect to work fine both on a live server and localhost?

This is not the "root directory" as you've stated in the question title; it's a subdirectory and that's the problem...

RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]

The rule already excludes the root directory - as it should. (This is achieved because the regex /(.*)/$ would fail to match the root).

The problem with this rule is you are trying to remove the trailing slash from every other URL, including subdirectories (as in physical filesystem directories). You can't do this - directories need the trailing slash*1. You would have the same problem on the live server if you requested a subdirectory. (I assume you do have subdirectories for assets, images, etc.?)

If you remove the trailing slash then mod_dir will (by default) append the slash again with a 301 redirect - resulting in an endless redirect loop.

(*1 You can suppress the trailing slash on directories, in terms of the URL you see - but the trailing slash still needs to be present in order to serve directory index documents from those directories. In order to achieve this you can internally rewrite the request to append the trailing slash - but this is messy - particularly when resolving canonicalization issues - and probably not necessary in your situation anyway.)

It's a simple fix... you basically need to check that the request does not map to a directory before removing the trailing slash.

Try the following instead:

# Removing trailing slashes from non-directory URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond ${REQUEST_URI} ^/(.+)/$
RewriteRule ./$ https://example/%1 [R=301,L]

Note that I've also included the scheme+hostname in the substitution string (as you have in the other canonical redirects) in order to minimise the number of redirects when also requesting HTTP and/or www (although these should be edge cases anyway).

You will need to clear your browser (and possibly other intermediary) caches before testing and test first with a 302 (temporary) redirect to avoid potential caching issues. 301 (permanent) redirects (including errors) are cached persistently by the browser.


when someone types d/file/ or d/file in the url bar, it loads the same content (duplicate content)

However, that is something you should really be controlling in your PHP router. Your PHP code must be resolving both requests into one for both URLs to return the same response - perhaps you should not be doing that. Then one or other URL (eg. the one with the trailing slash) will naturally result in a 404 (assuming that's what your router does). Or redirect one to the other in your PHP router/script - by doing this in PHP you can selectively redirect only the URLs that need redirecting and not URLs that would otherwise result in a 404 anyway.

This also avoids the need to explicitly check for physical directories, since requests for physical directories are not hitting your router.


Aside:

On localhost, localhost/mydomain/folder/file/ redirects fine,

Instead of simply using a subdirectory off the localhost, why don't you define the <VirtualHost> ServerName and DocumentRoot properly for mydomain - or perhaps use a subdomain like local.mydomain if you need to keep mydomain (the live site) accessible? Then you have the same directory structure on both local and live sites.

(It could still be stored as a subdirectory off the localhost's document root if you wish, but the files could literally be stored anywhere.)

It’s a tricky situation because your redirect rule works well on a live domain but on localhost it creates a redirect loop—likely due to the way the URL is structured on localhost (e.g., having an extra directory in the path).

You can try:

RewriteCond %{REQUEST_URI} !^/$
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L]

本文标签: phphtaccess remove trailing slash on root directory redirecting too many timesStack Overflow