Close and Go BackBack to Viget

No Query String? No Problem.

Patrick Reagan
Patrick Reagan, Development Director, March 19, 2008 5

When rewriting URLs on your site with mod_rewrite, you’ll typically want to preserve the query string while redirecting your users to the new location.  You can accomplish this by either clobbering the existing query string:

RewriteRule ^category/tech/?$ http://www.viget.com/extend/ [R=301,L]

Or appending to an existing one (with the QSA option):

RewriteRule ^category/tech/?$ http://www.viget.com/extend/ [QSA,R=301,L]

Both of these rules assume that you want to preserve the query string, but what if you want to remove it entirely?  We needed to do exactly that when moving the existing Viget site over to its new incarnation.  Instead of our news items having antiquated ID-based URLs, each post now has a nice SEO-friendly “slug.” A quick attempt at redirecting one of these news items looked like this:

RewriteCond %{QUERY_STRING} ^id=1889
RewriteRule ^news-detail.html$ http://www.viget.com/blog/nixon_reagan_williams_featured_in_computerworld/ [R=301,L]

If we dissect this, the rule states: for a query string containing ‘id=1889’, permanently redirect the ‘news-detail.html’ URL to this new one and don’t process any other rules.  When it came time to test it out, it mostly worked, but would append ?id=1899 to the URL.  Even though we didn’t specify how to handle query strings, the original was added to the end of the URL – something we definitely didn’t want.  The official mod_rewrite documentation yielded this tip:

By default, the query string is passed through unchanged. You can, however, create URLs in the substitution string containing a query string part. Simply use a question mark inside the substitution string to indicate that the following text should be re-injected into the query string. When you want to erase an existing query string, end the substitution string with just a question mark. To combine new and old query strings, use the [QSA] flag.

After simply adding a question mark to the rewritten URL, we now had the desired behavior:

RewriteCond %{QUERY_STRING} ^id=1889
RewriteRule ^news-detail.html$ http://www.viget.com/blog/nixon_reagan_williams_featured_in_computerworld/? [R=301,L]

Try it out for yourself.

Stephanie Hay said on 03/19 at 12:57 PM

PS: We edited several titles upon import, but it was easy peasy going through the rewrite doc to overwrite old slugs with the new.  Sweet solutions FTW!

Jonathan said on 03/20 at 03:14 AM

Thanks for your article this is really helpful

Tony Pitale said on 03/20 at 06:01 AM

I’d be interested in seeing how nginx might handle this. Thanks though, very helpful.

Patrick Reagan said on 03/21 at 08:23 PM

@Jonathan: Thanks!

@Tony: I’d be interested as well, sounds like you’ve got an idea for your first post on the Viget blog.

Rob Ares said on 03/23 at 07:23 AM

@tony

i think the rule in ngnix would look similar (if not more concise):

if ($query_string ~* ^id=1889$) {
rewrite ^news-detail.html$ http://www.viget.com/blog/nixon_reagan_williams_featured_in_computerworld/ permanent;
break;
}

this can also be done in 1 line:

rewrite ^news-detail.html?id=1889$ http://www.viget.com/blog/nixon_reagan_williams_featured_in_computerworld/ permanent;

none of these take in account additional rules placed ahead of them (which usually is a consideration). hope this helps!

Name:

Email:

URL:

Remember my personal information

Notify me of follow-up comments?

A Development Community for Viget Labs and Beyond

Every team member here at Viget Labs strives to be an innovator. We members of the development team are no different - that's why we're constantly engaging in community discussions and exploring the unknown that is the next generation of open-source web applications.

Viget Is Hiring!

Viget has job openings for Ruby Developers, Interns, and Front-End Developers. Learn More »

Recent Comments

I might be missing something but couldn’t a clever person spoof the cookie?