I want to "canonicalize" URLs for my static (files and folders) website.
The 'Aims' describes what I want to accomplish. The 'Code' gives my current .htaccess
.
Everything works right now, but I wonder if the code could be improved:
- any changes for better performance?
- can some rules be removed?
- can some rules be merged?
- can something be shortened?
- are some explaining comments wrong?
In my .htaccess
there shouldn't be anything else as what is described in 'Aims' and my examples. So if there should be something that has nothing to do with it, it is probably unneeded (if I don't miss an important part right now).
Aims
- Strip the file ending
.html
(but keep all other endings). - if the file is
index.html
, strip "index", too, and don't keep a (folder) trailing slash - no trailing slashs for files or folders
- if someone adds a trailing slash, redirect to variant without
Example 1
- Physical file:
example.com/foo/bar.html
- Desired URL:
example.com/foo/bar
- URLs that should redirect (301) to desired URL:
example.com/foo/bar.html
example.com/foo/bar/
Example 2 (if index.html
)
- Physical file:
example.com/foo/index.html
- Desired URL:
example.com/foo
- URLs that should redirect (301) to desired URL:
example.com/foo/index.html
example.com/foo/index
example.com/foo/
example.com/foo.html
Example 3 (if non-HTML file)
- Physical file:
example.com/foo/bar.png
- Desired URL:
example.com/foo/bar.png
(= same as physical) - URLs that should redirect (301) to desired URL:
- none
Code (.htaccess
)
# Turn MultiViews off. (MultiViews on causes /abc to go to /abc.ext.)
Options +FollowSymLinks -MultiViews
# It stops DirectorySlash from being processed if mod_rewrite isn't.
<IfModule mod_rewrite.c>
# Disable mod_dir adding missing trailing slashes to directory requests.
DirectorySlash Off
RewriteEngine On
# If it's a request to index(.html)
RewriteCond %{THE_REQUEST} \ /(.+/)?index(\.html)?(\?.*)?\ [NC]
# Remove it.
RewriteRule ^(.+/)?index(\.html)?$ /%1 [R=301,L]
# if request has a trailing slash
RewriteCond %{REQUEST_URI} ^/(.*)/$
# but it isn't a directory
RewriteCond %{DOCUMENT_ROOT}/%1 !-d
# and if the trailing slash is removed and a .html appended to the end, it IS a file
RewriteCond %{DOCUMENT_ROOT}/%1.html -f
# redirect without trailing slash
RewriteRule ^ /%1 [L,R=301]
# Add missing trailing slashes to directories if a matching .html does not exist.
# If it's a request to a directory.
RewriteCond %{REQUEST_FILENAME}/ -d
# And a HTML file does not (!) exist.
RewriteCond %{REQUEST_FILENAME}/index.html !-f
# And there is not trailing slash redirect to add it.
RewriteRule [^/]$ %{REQUEST_URI}/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -d
# And a HTML file exists.
RewriteCond %{REQUEST_FILENAME}/index.html -f
# And there is a trailing slash redirect to remove it.
RewriteRule ^(.*?)/$ /$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} -d
# And a HTML file exists.
RewriteCond %{REQUEST_FILENAME}/index.html -f
# And there is no trailing slash show the index.html.
RewriteRule [^/]$ %{REQUEST_URI}/index.html [L]
# Remove HTML extensions.
# If it's a request from a browser, not an internal request by Apache/mod_rewrite.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# And the request has a HTML extension. Redirect to remove it.
RewriteRule ^(.+)\.html$ /$1 [R=301,L]
# If the request exists with a .html extension.
RewriteCond %{SCRIPT_FILENAME}.html -f
# And there is no trailing slash, rewrite to add the .html extension.
RewriteRule [^/]$ %{REQUEST_URI}.html [QSA,L]
</IfModule>
(some parts of this file are by Jon Lin over at Stack Overflow)