RewriteRule: removing the querystring in Apache < 2.4

Apache 2.4 adds the [QSD] flag to the RewriteRule directive. QSD stands for Query String Discard and according to Apache this flag serves to simplify common rewriting scenarios.

RewriteRule's default behaviour appends any query string from the incoming URL to the outgoing URL, provided that the outgoing URL itself has no query string. Adding the [QSD] flag prevents this behaviour. 

When the requested URI contains a query string, and the target URI does not, the default behavior of RewriteRule is to copy that query string to the target URI. Using the [QSD] flag causes the query string to be discarded.

A useful addition to the already extensive capabilities mod_rewrite offers. Look for instance at the following real world example in which, on the renewal of one of our clients websites, the old query string based paths are replaced with friendly URLs:

RewriteCond %{QUERY_STRING} ^main_page=index&cPath=8$
RewriteRule ^(.*)$ /over-ons/onze producten [L,R=301]

In fact this code leads to an infinite loop: as RewriteCond is based on the query string which is added to the outgoing URL by RewriteRule, mod_rewrite will keep redirecting the URL until either Apache or the browser gives up. Adding the [QSD] flag will make the above redirect run smoothly.

RewriteCond %{QUERY_STRING} ^main_page=index&cPath=8$
RewriteRule ^(.*)$ /over-ons/onze producten [L,R=301,QSD]

QSD before Apache 2.4

The [QSD] flag is available as of Apache 2.4. If you run earlier version of the HTTPD server then you will have to do without this flag, in which case the above code may not only lead to an infinite loop but to sleepless nights as well. Because how can you induce Apache not to carry out this redirect more than once?

The solution is as unexpected as it is simple: as stated above RewriteRule only appends the query string to the outgoing URL if the outgoing URL itself has no query string! Now, by appending a ? (question mark) to the rewrite rule, RewriteRule will consider the outgoing URL to contain a query string and hence doesn't append the incoming query string. Lastly this lone question mark is removed from the URL (apparently it is considered redundant junk) so that we're left with a clean and well working outgoing URL.

RewriteCond %{QUERY_STRING} ^main_page=index&cPath=8$
RewriteRule ^(.*)$ /over-ons/onze producten? [L,R=301]