HTAccess RewriteRule, When it Changes the URL in the Address Bar

Thursday, December 24th 6:04pm Matt

I have been trying to figure this out for ages. When will RewriteRule change the URL in the browser address bar? Today I read thought the whole Apache mod_rewrite documentation page and I still didn’t know the answer. But after a ton of searching I finally figured it out, and hope to explain it to you the way I wish someone would have explained it to me from the beginning.

To start off, I think part of the reason this isn’t explained in a more upfront manner is because the writers of the documentation don’t really think it’s a valid question. Yes, if you’re where I was this morning that sounds ridiculous, and it is, but now I can understand their point of view.

The first rule of RewriteRule is:

RewriteRule never “changes” the URL in the user’s browser window.

Right now you’re probably saying no way, you’ve seen it happen, so you know it must be happening somehow. The end result is happening, you are correct, but it’s not happening the way you might think. RewriteRule does not say to the browser, “Please change the URL in the address bar to this.” Instead, sometimes RewriteRule says, “Oh, the page you’re looking for doesn’t exist, try this one instead.” This is called a redirection.

Rewrite versus Redirection

This is a very important distinction to most of us, but it is sort of glossed over in the Apache documentation because its writers forgot how revolutionarily important it is.

A rewrite is when Apache says, “OK, I am going to handle your request, and internally I am going to change the URL to this other URL. You are never going to see that other URL, but that is the URL that is going to be processed. You will continue to see whatever it is you typed in your browser’s address bar.”

A redirection is when Apache says, “Oh, I recognize that I can’t help you with this request, I suggest you ask for this URL instead.” After it says this, it’s done with you, the request is completely finished, and it has forgotten you ever existed. Your browser, however, receives this information and says, “Well if they suggest a different URL, I guess I’ll do my user a favor and request that URL next. Oh, and so my user knows what’s going on I’ll change the URL in the address bar.” Next your browser makes a whole separate request with the new URL. The brand new request is received by the web server and processed. The web server has no knowledge that these two requests are in any way related, and the web server certainly isn’t the one who changed the URL in the address bar of your browser.

This is a big deal! It’s totally lost on the writers of the Apache documentation. Because now you know you can effectively do the two things you want to do: change the URL internally or change the URL externally (or both, but in two steps.)

The Code

So what’s the difference between a rewrite and a redirect? One letter: R.

Rewrite

RewriteRule ^/cars/acura /cars/honda

Users who request the URL /cars/acura will still see /cars/acura in their address bar but they’ll see the content as if they had requested /cars/honda. (This is just an example and would lead to duplicate content warnings in Google because two different pages would have the same content.)

A better example:

RewriteRule ^/cars/(.*) /cars.php?make=$1 [QSA]

This will internally rewrite requests to /cars/acura to /cars.php?make=acura so you can pretty up your URL structure. It will handle those requests at the same time. The QSA stands for “Query String Append” and means that if the URL came in with additional query string info that will also be appended, not lost.

Redirect

RewriteRule ^/cars/acura /cars/honda [R]

This is the exact same example as the first example above except for the [R]. The R says, do a redirect which means once Apache is done processing the RewriteRule directives, it will stop processing the request and send the redirect message back to the browser as we discussed at the beginning of this post. This means the browser will most likely change the URL in the address bar and make a new request. There will be two web server requests, which are totally unrelated as far as the web server is concerned.

I should say, for the record, that normally the above code would be written as:

RewriteRule ^/cars/acura /cars/honda [R=301,L]

By default R returns code 302, meaning “moved temporarily” which isn’t often what people like you and me want. We want 301, meaning “moved permanentaly” which will also direct search engines to update their URL. The L means if a URL has matched this directive, do the redirect immediately and don’t process any more directives. Most of the time we don’t have complex sets of directives that all need to be processed, so just get out early to improve performance.

More on Redirects

I won’t go into detail here, but there are more things than just [R] that will force a redirect, for instance if you’ve given a substitution URL on another domain. Read the docs for more of those types of situations.

Conclusion

Hopefully this has been as helpful to you as finally figuring this out has been to me. It feels so good to finally have a good grasp on this topic.

1

Jesse

Wednesday, March 10th 1:31pm

What are the reasons that the new address might be displayed even though the [R]edirect flag was not used?

2

Matt

Wednesday, March 10th 3:19pm

If you specify a rewrite rule where the destination url is fully qualified (starts with http://) and points to different website, then there will be no choice but to do a redirect and that will force the url in the address bar to change as it would with any redirect.

You can’t do a rewrite to another website.

3

Jesse

Wednesday, March 10th 4:35pm

Thanks. I found out that in my situation mod_dir was redirecting requests for folders to a default file. This is happening after mod_rewrite applied some rules so the rewritten address is getting index.nnn appended to it and the rewritten address is visible. I’m not sure how to remedy this situation yet.

Submit a Comment