Return a 404 Not Found status code when the ItemNotFound page is loaded

20 november 2012 om 00:00 by Ruud van Falier - Post a comment

When Sitecore can't find the requested item, it will redirect the user to the page that is configured in the setting ItemNotFoundUrl.
The problem is that redirecting will return an HTTP status code 302 (Moved Temporarily) and what we really want is the status code 404 (Not Found).

I've seen solutions where people will set the status code on the 'ItemNotFound' page.
That does not solve anything because the client will still be redirected to the ItemNotFound page and the initial request will not be marked as not found.

To solve this problem you can implement this custom pipeline processor.
It overrides the method that is called when Sitecore redirects the client to the ItemNotFound page.
Instead of redirecting, it does an HTTP request to retrieve the content of the ItemNotFound page and then it writes it to the client together with a 404 Not Found status code.

Keep in mind that:

  • The hostname of your website should be available on the server (some servers don't have a DNS, in that case you can add it to the hosts file)
  • Information about cookies is not submitted during the internal request of the ItemNotFound page, so if you have personalised information on that page, it will not work

To implement my solution,
add this to your include config file or add the processor to your web.config as a replacement of the default ExecuteRequest processor:

<pipelines>
  <httpRequestBegin>
    <processor type="ParTech.Library.Pipelines.ExecuteRequest, ParTech.Library" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel']"/>
    <processor type="Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel">
      <patch:delete />
    </processor>
  </httpRequestBegin>
</pipelines>

Add this class to your solution:

namespace ParTech.Library.Pipelines
{
    public class ExecuteRequest : Sitecore.Pipelines.HttpRequest.ExecuteRequest
    {
        protected override void RedirectOnItemNotFound(string url)
        {
            var context = System.Web.HttpContext.Current;

            try
            {
                // Request the NotFound page
                string domain = context.Request.Url.GetComponents(UriComponents.Scheme | UriComponents.Host, UriFormat.Unescaped);
                string content = Sitecore.Web.WebUtil.ExecuteWebPage(string.Concat(domain, url));

                // Send the NotFound page content to the client with a 404 status code
                context.Response.TrySkipIisCustomErrors = true;
                context.Response.StatusCode = 404;
                context.Response.Write(content);
            }
            catch (Exception)
            {
                // If our plan fails for any reason, fall back to the base method
                base.RedirectOnItemNotFound(url);
            }

            // Must be outside the try/catch, cause Response.End() throws an exception
            context.Response.End();
        }
    }
}

The result in Firebug after requesting a non-existing item: