Question

I have multilingual website and I want a custom 404 page in all languages which depends on the context of the site. What is the correct approach to get the 404 page defined in content tree or to access 404 page from content tree? I am able to get 404 page if I will define that in my site root but not from content tree.

enter image description here

I want 404page from the content tree as my 404 Custom redirect.

My Webconfig setting:

<setting name="ItemNotFoundUrl" value="/404Page.aspx" />

IIS 404 entry. enter image description here

The error i got when page is not there in sitecore:

After changing IIS to default and setting httpErrors like

  <error statusCode="404" path="/404PAGE.aspx" responseMode="ExecuteURL" />

</httpErrors>

enter image description here

Was it helpful?

Solution

I use a custom implementation of the ExecuteRequest processor in the httpBeginRequest pipeline.
That is where the 404 requests are eventually handled.

You can override the RedirectOnItemNotFound method in there and add some logic to load a different 404 page per site.

Take a look at this blog post that explains how to implement it.

EDIT: I have added an example of how to implement it so you can return a site specific 404 page.

If you make this modification, you can return a different 404 page per site:

Add this to the configuration:

<setting name="NotFoundPage.SiteName1" value="/not-found.aspx" />
<setting name="NotFoundPage.SiteName2" value="/not-found.aspx" />

Then in the custom RedirectOnItemNotFound code, do this to return site specific 404 content:

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

        try
        {
            // Get the domain of the current request.
            string domain = context.Request.Url.GetComponents(UriComponents.Scheme | UriComponents.Host, UriFormat.Unescaped);

            // Get 'not found page' setting for current site.
            string notFoundUrl = Sitecore.Configuration.Settings.GetSetting(string.Conact("NotFoundPage.", Sitecore.Context.Site.Name));

            // Request the contents of the 'not found' page using a web request.
            string content = Sitecore.Web.WebUtil.ExecuteWebPage(string.Concat(domain, notFoundUrl));

            // Send the 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 idea is that you use the site name as setting key so you can resolve the configuration value per site.
The code needs some work of course, but you get the idea..

EDIT 2: Added example configuration to replace the original pipeline processor with the new one:

<pipelines>
  <httpRequestBegin>
    <processor type="Sitecore.Pipelines.HttpRequest.ExecuteRequest, Sitecore.Kernel">
      <patch:attribute name="type">ParTech.Pipelines.ExecuteRequest, ParTech</patch:attribute>
    </processor>
  </httpRequestBegin>
</pipelines>

OTHER TIPS

Sitecore does some of its own "item not found" handling, and also doesn't do a good job of handling 404s in an SEO-friendly manner.

The best solution I've found for handling 404s and other errors in Sitecore is the Sitecore Error Manager.

http://marketplace.sitecore.net/en/Modules/Sitecore_Error_Manager.aspx

https://github.com/unic/SitecoreErrorManager/wiki

You can set ItemNotFoundUrl in Sitecore config to any item in the content tree, it does not need to be in the site root, and as long as you don't specify a language it will use whatever the user has been browsing the site in (or default for first visit). The item has to be in the same tree structure for all sites though:

<setting name="ItemNotFoundUrl" value="/errors/404.aspx" />
<setting name="LayoutNotFoundUrl" value="/errors/500.aspx"/>
<setting name="NoAccessUrl" value="/errors/403.aspx"/>

Techphoria414 is right that Sitecore out of the box does not do a good at handling 404s in an SEO friendly manner, it will do a 302 redirect to the error page. However, if you set the following to true then a Server.Transfer will be used:

<!--  USE SERVER-SIDE REDIRECT FOR REQUEST ERRORS
    If true, Sitecore will use Server.Transfer instead of Response.Redirect to redirect request to service pages when an error occurs (item not , access denied etc).
    Default value: false
-->
<setting name="RequestErrors.UseServerSideRedirect" value="true"/>

Which triggers the following code in the ExecuteRequest pipeline.

protected virtual void PerformRedirect(string url)
{
  if (Settings.RequestErrors.UseServerSideRedirect)
    HttpContext.Current.Server.Transfer(url);
  else
    WebUtil.Redirect(url, false);
}

You can read more about it in this blog post. Be sure to set Status property of the current System.Web.HttpResponse to 404 in your code that handles it. There is more info in the Handling HTTP 404 document.

Error Manager is a great module though and is much more flexible if you need to set different url locations for different sites.

I have written a blog post on this, might be useful for someone in future.

http://sitecoreblog.tools4geeks.com/Blog/35/Better-way-of-handling-sitecore-404-pages

The approach i have taken is :

  • Add a processor after HttpRequest.ItemResolver on HttpRequestBegin pipeline.
  • Find if context item is null, if null set 404 content page as context item.
  • Add another processor in the pipeline httpRequestEnd after EndDiagnostics processor to set the 404 status code for not found Item.

With this approach, we don't need to set 404 status code on Renderings. As we are setting it at the end of "httpRequestEnd" pipeline. /404 page returns 200 status code as this page suppose to return 200 status code.

works in multi-site/multi-language environment.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top