Reputation: 31
Been trying to play with mod_rewrite through .htaccess
in one Xampp virtualhost, but I am not getting the results that I am looking for.
What I am tring to do is to rewrite the following: www.example.com/name/billy.html
to: www.example.com/billy
Without trying to rewrite the URLs the virtualhost is working fine, I have access to all pages. However, when I add the .htaccess
with the corresponding rewrite rule I get a 404 page not found. The regex is working as expected though. I see that the request to www.example.com/name/billy.html
it's been rewritten to www.example.com/billy
, but the page doesn't load.
The name
folder exists in the file structure and the .htaccess
is inside the example
folder.
Currently, my vh configuration looks like this:
<VirtualHost *:80>
DocumentRoot "/Applications/XAMPP/xamppfiles/htdocs/example"
ServerName www.example.com
<Directory "/Applications/XAMPP/xamppfiles/htdocs/example">
Options Indexes FollowSymLinks ExecCGI Includes
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
And this is the content of the .htaccess
file:
RewriteEngine On
RewriteRule ^name\/([a-z]+).html$ /$1 [L,NC,R]
What is missing?
Upvotes: 3
Views: 836
Reputation: 45829
What I am tring to do is to rewrite the following:
www.example.com/name/billy.html
to:www.example.com/billy
You seem to have the process the wrong way round and possibly mixing up "rewrites" and "redirects"?
You should be internally rewriting from the visible "friendly" URL to the underlying file-path that actually handles the request. You are trying to do the opposite here. How is your system expected to handle a request for /billy
? (It doesn't, and generates a 404.)
You may be thinking you can change the URL using .htaccess
(mod_rewrite) alone? But no, that is not how this works.
RewriteRule ^name\/([a-z]+).html$ /$1 [L,NC,R]
You mention "rewrite", but this directive is in fact a "redirect" (as indicated by the R
flag). Specifically, a 302 (temporary) redirect in this instance.
(You might actually want to implement a redirect like this, if you are changing an existing URL structure, but more on that later*1)
A URL "rewrite" is entirely internal to the server. The user only sees the public URL, they do not see the URL that it might be rewritten to. You (the user) can't "see" a rewrite.
A "redirect" on the other hand, usually refers to an external redirect, ie. a 3xx response sent back to the client with an instruction to make a new request to a different URL. The URL being redirected to is visible to the user. This is used when content has moved to a different URL.
So, following your example, you should be requesting/linking to (in your HTML source) the short/friendly URL /billy
and internally rewriting the request to /name/billy.html
that actually handles the request.
For example:
RewriteEngine On
# Rewrite from "billy" to "name/billy.html"
RewriteRule ^[a-z]+$ name/$0.html [NC,L]
The $0
backreference contains the entire URL-path that is matched by the RewriteRule
pattern.
Only use the NC flag if you do need to match uppercase letters as well. But a request for /Billy
won't serve /name/billy.html
on a case-sensitive OS.
And that's really it, with regards to the URL-rewritting, you can stop reading here.
Regarding the external "redirect" mentioned above. You might choose to implement a redirect (in the opposite direction) if you are changing an existing URL structure and the old URLs have been indexed by search engines and/or linked (or bookmarked) to by external third parties - in order to preserve SEO and keep users happy.
For example, say your original URLs were of the form /name/billy.html
and you later decided to change your URLs to /billy
instead. You first change the URLs in the HTML source and implement the "rewrite" as mentioned above so the new URLs now work. You then might implement an external redirect from the old /name/billy.html
URL to the new /billy
URL.
For this, you would use a directive like you had initially, except you have to be careful of redirect-loops because you are already rewriting the request in the opposite directive. You only want to redirect "direct/initial" requests and not rewritten requests by the earlier rewrite (that is actually later in the file). An easy way to check for "direct" requests is to check against the REDIRECT_STATUS
environment variable, which is empty on the initial request and set to 200
(as in 200 OK status) when the request is rewritten.
For example, the following "redirect" would go before the above "rewrite", immediately after the RewriteEngine
directive:
# Redirect from "name/billy.html" to "/billy"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^name/([a-z]+)\.html$ /$1 [R=301,NC,L]
This should ultimately be a 301 (permanent) redirect since the URL has presumably changed permanently. However, always test with 302 (temporary) redirects to avoid potential caching issues.
Further reading:
Upvotes: 1