Somacon.com: Articles on web development, software, and hardware
§ Home > Index > Web Development

Permanent Redirect with HTTP 301

This article describes how to properly redirect a web page using an HTTP 301 status code and Location header. The 301 status code is used to indicate that a page has permanently moved. Multiple techniques are presented with recommendations.

In order to redirect an out-of-print web page to another location, return the HTTP 301 status code and a location header in the HTTP response of the deprecated web page. The HTTP 301 response code will tell user-agents that the location has permanently moved. This is particularly useful for search engines like Google, which will carry over page rank to the new page if this status code is seen. If you do not need to indicate permanent displacement, you can accomplish redirection by setting a Location header in PHP or using Response.Redirect in ASP. The location header does the actual redirection to the new location, and can be used by itself.

HTTP headers are sent for every web page. If you want to see what HTTP headers look like for a particular page, visit Rex Swain's HTTP Viewer. For advanced users, I would recommend you download the Firefox web browser and install Chris Pederick's Web Developer Extensions. Then, use the Information->View Response Headers function. In scripts, HTTP headers must be sent before sending any page content, including white space, or else an error will result.

HTTP 301 Redirect in ASP-VBScript

<%@ Language=VBScript %>
<%
' Permanent redirection
Response.Status = "301 Moved Permanently"
Response.AddHeader "Location", "http://www.somacon.com/"
Response.End
%>

In Active Server Pages (ASP), Response.Redirect does not work the same as the code shown in the example. Response.Redirect will set the location header as shown, but it will set the status code to HTTP/1.1 302 Object moved instead. When you set the Location header with Response.AddHeader, the status code must be manually defined, otherwise it stays 200 OK.

If you send any page content prior to the headers, you will get an error like, "Response object error 'ASP 0156 : 80004005'; Header Error; The HTTP headers are already written to the client browser. Any HTTP header modifications must be made before writing page content.". Normally, you do not see this error even if there is content prior to the redirect, because page buffering is enabled by default in IIS. If you want to be sure there is no content being sent before the redirect, call Response.Flush just before it, disable page buffering with Response.Buffer = False, or configure IIS to disable page buffering. (Disabling buffering reduces performance.)

HTTP 301 Redirect in PHP

<?php
// Permanent redirection
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://www.somacon.com/");
exit();
?>

If you set the Location header by itself, PHP automatically sets the status code to HTTP/1.1 302 Found.

Note, if you attempt to send headers after content has been sent, you will get a warning like, "Warning: Cannot modify header information - headers already sent by ...". Watch out for empty lines and spaces between PHP open and close tags. ASP ignores these, but PHP does not.

HTTP 301 Redirect in ColdFusion

<CFHEADER statuscode="301" statustext="Moved Permanently">
<CFHEADER name="Location" value="http://www.somacon.com/">

Do not use a CFFLUSH command before the above tags, or in Application.cfm. This Coldfusion code was provided by Toll Free Forwarding.com.

HTTP 301 Redirect in Perl

#!/usr/bin/perl      -w
use strict;
print "Status: 301 Moved Permanently\n";
print "Location: http://somewhere/page.htm\n\n";
exit;

As in PHP, if you do not supply the 301 code explicitly, Apache will send a "302 Found" status code. Note the subtle difference as compared to PHP. This example prints a "Status" header rather than an HTTP status code line. This is because you can not set the HTTP status code directly as you typically can in PHP. If you do, the server will return a 500 Internal Server Error, and the error log will show:

malformed header from script. Bad header=HTTP/1.1 301 Moved Permanently: /cgi/test.pl

The "Status" header is an alternative way of setting the HTTP status code. This is not passed to the browser directly, but the web server (Apache) converts it into a suitable HTTP status code. (The CGI specification does not allow directly setting the HTTP status code. Perl typically runs as a CGI, whereas PHP does not. For more information, see this PHP header FAQ or the PHP header function documentation.)

You must supply the carraige returns as specified above. Two carriage returns (\n\n) are needed after the last header, since they signify the end of the HTTP header and the beginning of content.

As in PHP, it is good practice to exit the script explicitly, otherwise, the Perl script continues executing. There should not be any print "Content-type: text/html\n\n"; or other output before printing these headers, or the headers will be printed as part of the content visible in the browser.

Redirection with mod_rewrite

The Apache module, mod_rewrite, is typically used to transform URLs from one form to another. It can also be used for permanent redirection. The rewriting rules can be placed in httpd.conf (for server-wide rules), or in .htaccess files (for directory-specific rules). Consider the following example that is in the .htaccess file of this website:

rewriteEngine on
rewriteRule ^contact\.php$ http://www.somacon.com/p2.php [R=permanent,L]

The first line tells Apache to turn the mod_rewrite engine on. The second line tells mod_rewrite to match requests where the URI is exactly contact.php. The ^ and $ match the beginning and end of the expression, respectively, and the \ is used to escape the period, which otherwise would match any character. After the match pattern is a space, and then the substitution. In this case, I want the server to substitute contact.php with http://www.somacon.com/p2.php.

In brackets are the comma-separated rule flags. The R=permanent flag tells Apache to issue a permanent redirect 301 response, with the location as the substituted URL. The L flag tells mod_rewrite that no other subsequent rules should be processed.

Note that I specified the full destination URL in the substitution, because otherwise mod_rewrite uses the short form of my hostname somacon.com. To avoid Google indexing issues, I've redirected all non-www traffic to the www prefixed host. I also redirect the default, index pages to the root directory. The rules to achieve this are as follows:

# redirect all non-www traffic
RewriteCond %{HTTP_HOST} ^somacon\.com$
RewriteRule ^.*$ http://www.somacon.com%{REQUEST_URI} [R=permanent,L]

# Redirect aliases of home page to the root website
rewriteRule ^index\.(php|html|htm) http://www.somacon.com/ [R=permanent,L]

I leave it up to the reader to understand this example by reading the mod_rewrite documentation. The mod_rewrite module offers a very powerful and effective way to perform redirection. It is preferable to use mod_rewrite over a server-side script. The drawback is the steep learning curve, requiring you to learn both its syntax and the syntax of regular expressions.

Redirection with Javascript or META tags

If you don't have server-side scripting or mod_rewrite on your web server, you can still do redirection, but not as elegantly. The Javascript/META method will redirect after both the headers and the page have loaded. By contrast, the HTTP header method described above redirects immediately after the headers have loaded. While both methods require two requests to the web server, the Javascript/META method causes the user's browser to flicker or refresh as the old page is loading. Redirection with HTTP headers is seamless, and saves time.

You can not send a 301 status code via Javascript or META tags. Since the HTTP status code of the page will remain 200 OK, most search engines will continue to think the location is valid. Any page rank of the old location will not be transferred to the new location.

Another disadvantage is that some browsers disable Javascript or META refresh. Therefore, one must include a link to the destination page in the body of the page. One can also add a delay between when the page is displayed, and when it redirects. However, I would strongly discourage this and will not even describe it here.

Unfortunately, it is very common to see delayed META/Javascript refresh used when a site or page has moved. The page typically shows a message saying, "This site has moved to ... Your browser will be automatically forwarded in X seconds. Click here if your browser does not automatically forward you." Some website, particularly government and legal websites, add such an intermediate page whenever you click a link to an external site.

Not only is this search-engine unfriendly, but it has the additional drawback of wasting the visitor's precious time while they read wholly unneccessary information and wait for the redirect. The first rule of web design (and writing) is to treat your reader's time with respect. All visitors except the most novice can tell when they are leaving your site for another, and that your site has no authority over the external site, so there is no need to waste everyone else's time.

Redirection with Javascript

<html>
<head>
<script type="text/javascript">
window.location.href='http://www.somacon.com/';
</script>
</head>
<body>
This page has moved to <a href="http://somacon.com/">http://somacon.com/</a>

</body>
</html>

Note that they syntax document.location=''; has been deprecated. Use the above code, or alternately, document.URL='';.

Redirection with META Refresh

<html>
<head>
<meta http-equiv="refresh" content="0;url=http://www.somacon.com/">
</head>
<body>
This page has moved to <a href="http://somacon.com/">http://somacon.com/</a>
</body>
</html>

As I've pointed out, the META refresh tag should be avoided as a method of redirection. There are other times when it is more useful. A common situation is on a page where information is constantly changing, like news or stock tickers. For example, most major news websites include META refresh tags in their home pages. CNN sets the refresh interval to 1800 seconds, while Google sets it to 900 and Yahoo, to 300. If the user switches to another application for awhile, when they return, they are presented with the most up to date information.

Another situation is in the status page for the execution of a long-running server-side task. A good site design principle is that every web page load within a fraction of a second. For longer tasks, queue and run them on the server, and simply show a status page via the web. The three states of the status page would be queued, running, and completed. The refresh tag would be printed in the queued and running states, with an appropriate refresh interval like 15 or 30 seconds. You should always put a link to manually refresh the status page, in case the user disabled this META tag in their browser.

Redirection Live Example

If you try to go to this page:
http://www.somacon.com/color/html_css_table_border_styles.php
You will automatically be redirected to this page via mod_rewrite:
http://www.somacon.com/p141.php
The actual HTTP headers for the old page are shown below. The headers were captured using the freeware utility, HTTPSpy.

HTTP/1.1 301 Moved Permanently
Date: Thu, 07 Apr 2005 18:52:27 GMT
Server: Apache/1.3.33 (Debian GNU/Linux) mod_throttle/3.1.2 mod_ssl/2.8.22 OpenSSL/0.9.7d
Location: http://www.somacon.com/p141.php
Keep-Alive: timeout=15, max=100
Proxy-Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=iso-8859-1
Via: 1.1 HttpSpy

HTTP/1.1 301 Status Code Definition

From the HTTP/1.1 Status Code Definitions section of the Hypertext Transfer Protocol -- HTTP/1.1 RFC 2616, Fielding, et al. See the RFC for all the possible redirection status codes, which include 300-Multiple Choices, 301-Moved Permanently, 302-Found, 303-See Other, 304-Not Modified, 305-Use Proxy, and 307-Temporary Redirect. Using the appropriate status code is worthwhile for public websites, but you can probably leave it unspecified when redirecting in a private or intranet application.

The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible. This response is cacheable unless indicated otherwise.

The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).

If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

Note: When automatically redirecting a POST request after receiving a 301 status code, some existing HTTP/1.0 user agents will erroneously change it into a GET request.


Created 2005-04-07, Last Modified 2013-07-18, © Shailesh N. Humbad
Disclaimer: This content is provided as-is. The information may be incorrect.