It’s a well known issue that when Sitecore displays a 404 page, it’s done by doing a 302 redirect to the 404 page, hence the 302 status code is thrown before the 404.
The behavior is partially because of the way .net handles redirects internally. But fortunately you can overcome it pretty easily.
My colleague Anders Laub came up with this extension to the Sitecore httpRequestBegin pipeline.
By adding a processor to the pipeline you can switch the missing item with a 404 item inside Sitecore. The item in Sitecore will then have a sublayout that will throw the 404. In effect, Sitecore (or .net) will not know that there is a page missing and will continue the business as usual. It’s up to us developers to handle the 404. Just like we like it.
First the httpRequestBegin processor:
<httpRequestBegin> <processor type="Sitecore.Pipelines.PreprocessRequest.CheckIgnoreFlag, Sitecore.Kernel" /> ... ... <processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel" /> <processor type="MyCode.Custom404ResolverPipeline, MyDll" /> ... ... </httpRequestBegin>
The processor is added just after the ItemResolver. The ItemResolver returns null if the item is not found.
We then switch the missing item with our 404 item:
public class Custom404ResolverPipeline : HttpRequestProcessor { public override void Process(HttpRequestArgs args) { Assert.ArgumentNotNull(args, "args"); // Do nothing if the item is actually found if (Sitecore.Context.Item != null || Sitecore.Context.Database == null) return; // all the icons and media library items // for the sitecore client need to be ignored if (args.Url.FilePath.StartsWith("/-/")) return; // Get the 404 not found item in Sitecore. // You can add more complex code to get the 404 item // from multisite solutions. In a production // environment you would probably get the item from // your website configuration. Item notFoundPage = Sitecore.Context.Database.GetItem("{DFE03D7A-00B9-4C15-8AB7-482D82B3484E}"); if (notFoundPage == null) return; // Switch to the 404 item Sitecore.Context.Item = notFoundPage; } }
The page we switched to needs to have a sublayout that will do the actual 404 return code:
public partial class _404 : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.NotFound; HttpContext.Current.Response.TrySkipIisCustomErrors = true; HttpContext.Current.Response.StatusDescription = "Page not found"; } }
Remember to set the TrySkipIisCustomErrors or your 404 page will be ignored by IIS 7.5.
MORE READING:
- Kern Herskind has another solution here.
- A Stackoverflow article on the same issue.
- Partech handles the issue as well.
Image may be NSFW.
Clik here to view.

Clik here to view.
