3
votes

I picked up the following code from Stackoverflow->a blog re handling custom 404 in Sitecore (which acutally does a 302 redirect to 404 page with status 200 which gets picked up by google as soft 404).

While this works totally fine in our local test servers, the moment we drop it in production the site goes haywire and takes AGES e.g. 8-9 minutes to load and stuff.

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

        try
        {
            // Request the NotFound page
            var domain = context.Request.Url.GetComponents(
                UriComponents.Scheme | UriComponents.Host, 
                UriFormat.Unescaped);

            var content = WebUtil.ExecuteWebPage(
                string.Concat(domain, url));

            // The line below is required for IIS 7.5 hosted 
            // sites or else IIS is gonna display default 404 page
            context.Response.TrySkipIisCustomErrors = true;
            context.Response.StatusCode = 404;
            context.Response.Write(content);
        }
        catch (Exception ex)
        {
            Log.Error(string.Format("Falling back to default redirection behavior. Reason for error {0}", ex), ex);

            // Fall back to default behavior on exceptions
            base.RedirectOnItemNotFound(url);
        }

        context.Response.End();
    }
} 

P.S: I then replaced ExecuteRequest with my custom one in web.config.

If you have experienced similar thing or know of any issue re this please do shed some light.

Thanks in advance

4
I'd have thought the call to WebUtil.ExecuteWebPage would be problematic in anything other that light traffic. Too many loop-back web requests firing off. If your 404 page somehow invokes a 404 itself, you may get into loop (maybe this is what's happening?) - Paul George

4 Answers

6
votes

There is a setting in Sitecore, with which you can get rid of the 302 redirect:

<setting name="RequestErrors.UseServerSideRedirect" value="true" />

With this settings, the url stays the same and the status code is 404. If you want to have some additional logic (like showing a Sitecore item as error page), there is a Shared Source module called Error Manager on the Sitecore Market Place.

Hope that helps.

0
votes

Check if the server is able to access the hostname of your website.

Servers often do not have access to a DNS and therefore are unable to resolve hostnames. In order for your 404 handler to work, the application needs to be able to access its own hostname to request the 404 page.

To be sure this works, edit the hosts file of the server and add an entry for your hostname there, pointing it to 127.0.0.1

0
votes

You can resolve it with creating new resolver. It is good solution when you want to give to an user error page in right language. But there some differences in IIS 7.0 and 7.5.

Add processor to your sitecore configuration:

<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel"/>
<processor type="Project.Error404Resolver, Project" />

Processor resolving it:

For IIS 7.0:

public class Error404Resolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
    public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
    {
        if(Sitecore.Context.Item == null && !args.Context.Request.Url.AbsolutePath.StartsWith("/sitecore")
        {
            args.Context.Response.Clear();

            SiteContext site = Sitecore.Context.Site;
            if(site != null)
            {
                Item item404Page = Sitecore.Context.Database.GetItem(site.RootPath + "website/error/404");
                if(item404Page != null)
                {
                    Sitecore.Context.Item = item404Page;
                    args.Context.Response.StatusCode = (int) System.Net.HttpStatusCode.NotFound;
                }
            }
        }
    }
}

For IIS 7.5:

public class Error404Resolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
    public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
    {
        if(Sitecore.Context.Item == null && !args.Context.Request.Url.AbsolutePath.StartsWith("/sitecore")
        {
            args.Context.Response.Clear();

            SiteContext site = Sitecore.Context.Site;
            if(site != null)
            {
                Item item404Page = Sitecore.Context.Database.GetItem(site.RootPath + "website/error/404");
                if(item404Page != null)
                {
                    WebClient webClient = new WebClient();
                    webClient.Encoding = args.Context.Request.ContentEncoding;
                    webClient.Headers.Add("User-Agent", args.Context.Request.UserAgent);
                    string page = webClient.DownloadString(LinkManager.GetItemUrl(item404Page));

                    args.Context.Response.StatusCode = (int) System.Net.HttpStatusCode.NotFound;
                    args.Context.Response.Write(page);
                    args.Context.Response.TrySkipIisCustomErrors = true;
                    args.Context.Response.End();
                }
            }
        }
    }
}

Whit this you will render error page in current page without redirect and returns to a browser code 404.

0
votes

I have the same issue at a customer I currently work at (looks like the code was pasted) and actually the reason is pretty obvious: If you execute this call with a url that is not registered in the Sitecore sites config (but accessible via IIS), you will also run through this code. Unfortunately, the WebUtil.ExecuteWebPage call is executed with the wrong url as well, hence you end up stuck in a loop.

Actually you should see a lot of these messages in your log: Falling back to default redirection behavior. Reason for error {0}, probably with timeouts.

If you really want to use your custom handler, you should check if you are in the right site context before calling WebUtil.ExecuteWebPage.