Response.Redirect and encoded URIs

Created 17th August, 2005 14:45 (UTC), last edited 23rd May, 2006 15:16 (UTC)

There appears to be a flaw in the way that Microsoft's IIS works with the Response.Redirect method. Well… Having had a chat with David Wang about it I can understand why it's done like it is, but that doesn't help those of us who like to do things properly/differently¹ [1Delete as applicable.].

If you look on-line all the examples seen will be in this sort of form:

<% Response.Redirect( "" ); %>

This works well for most sorts of redirects, but what happens when you have a URI with a space in it? All seems well if you do this:

<% Response.Redirect( " and encoded URIs" ); %>

But if you have already correctly encoded the URL then it breaks:

<% Response.Redirect( " URIs" ); %>

This is because the Response.Redirect takes what may be called a speculative approach to deciding how to encode the URL that you provide to it. This helps most ASP programmers to get the correct behaviour but means that the code is not compatible with, for example, redirecting back to a HTTP referrer² [2HTTP_REFERER—it is spelled incorrectly in the standard.] because this is already encoded. Thankfully it is pretty easy to fix.

Types of redirect

If you take a read through the HTTP standard (and you shouldn't be doing any web development without doing so) you will notice that there are many ways of doing redirects. Each one means something slightly different and they are used in different circumstances. Here is a recap of the ones you're likely to want to use:

  • 301—Used to tell the user agent (browser) that the resource is never going to be at this address again.
  • 302—A general purpose redirect and probably the most common sort. If in doubt use this one.
  • 303—Redirect with GET. Use this when you are redirecting after processing a form which uses POST.
  • 307—Temporary redirect. Use this where you are redirecting for things like error conditions, for example a redirect to a page informing the user of a database error.

You need to set one of these numbers in the Response.Status field (for a normal page this would be 200 meaning OK). You also need to write a Location header and depending on the method used in the request you should also include a short message body.

Message body

There are three methods that are important to redirects, GET, POST and HEAD. If the user agent has sent a HEAD request then you do not need to send a message body, and indeed you shouldn't send one.

A minimal body for a redirect that you expect to generate in response to a GET is outlined below:

  <h1>Page moved<h1>
  <p>The page you want <a href="newURL.html">has been moved<></p>

If the redirect is due to a POST from the user agent then you should use a message body like this:

  <h1>Page moved</h1>
  <p>The page you want has been moved</p>
  <form action="newURL.asp" method="POST">
    <p><input type="Submit" value="Go There" id="submit"></p>

Don't forget that if you're doing this you will need to add any parameters in as input hiddens and you will probably also want to change the button text and id to match what the resulting script expects.

Never use a HTTP refresh meta tag on this page (or on any other page); read the W3C's page on performing redirects; don't irritate your users!

Some code

It's always helpful to have a bit of code. This is the redirect function that is called after a forum post has been written to the database:

function Redirect( url ) {
	Response.Status = "303 See Other";
	Response.AddHeader( "Location", url );
	Response.Write( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ' +
			'"">\n' +
		'<html><head><title>Redirection</title></head>' +
		'<body><h1>Page moved</h1>' +
			'<p>The page you want <a href="' + url + '">has been moved</a>' +
		'</p></body></html>' );

Remember that the URL must be correct for this to work. No shirking by being sloppy when you do the encoding!