Htaccess: add/remove trailing slash from URL
Solution 1:
Right below the RewriteEngine On
line, add:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R] # <- for test, for prod use [L,R=301]
to enforce a no-trailing-slash policy.
To enforce a trailing-slash policy:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*[^/])$ /$1/ [L,R] # <- for test, for prod use [L,R=301]
EDIT: commented the R=301
parts because, as explained in a comment:
Be careful with that
R=301
! Having it there makes many browsers cache the .htaccess-file indefinitely: It somehow becomes irreversible if you can't clear the browser-cache on all machines that opened it. When testing, better go with simpleR
orR=302
After you've completed your tests, you can use R=301
.
Solution 2:
To complement Jon Lin's answer, here is a no-trailing-slash technique that also works if the website is located in a directory (like example.org/blog/):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [R=301,L]
For the sake of completeness, here is an alternative emphasizing that REQUEST_URI
starts with a slash (at least in .htaccess
files):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /(.*)/$
RewriteRule ^ /%1 [R=301,L] <-- added slash here too, don't forget it
Just don't use %{REQUEST_URI} (.*)/$
. Because in the root directory REQUEST_URI
equals /
, the leading slash, and it would be misinterpreted as a trailing slash.
If you are interested in more reading:
- PR 3145 for Laravel
- A discussion on commit 343c31e
(update: this technique is now implemented in Laravel 5.5)
Solution 3:
This is what I've used for my latest app.
# redirect the main page to landing
##RedirectMatch 302 ^/$ /landing
# remove php ext from url
# https://stackoverflow.com/questions/4026021/remove-php-extension-with-htaccess
RewriteEngine on
# File exists but has a trailing slash
# https://stackoverflow.com/questions/21417263/htaccess-add-remove-trailing-slash-from-url
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?(.*)/+$ /$1 [R=302,L,QSA]
# ok. It will still find the file but relative assets won't load
# e.g. page: /landing/ -> assets/js/main.js/main
# that's we have the rules above.
RewriteCond %{REQUEST_FILENAME} !\.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^/?(.*?)/?$ $1.php