Handling custom 404 error in Sitecore SXA
Default 404, 500 error pages in Sitecore SXA
Sitecore SXA module comes with custom 404 and 500 error pages out of the box. We can have a custom 404 error page configured from the Settings Items as shown below in the Settings item.
Custom 404 error page content in Sitecore SXA
Even though SXA handles the item not found cases and shows a 404 error page out of the box, there could be scenarios where you might want to throw a 404 status and show the 404 error page content. Writing a custom ItemResolver pipeline processor alone will not solve the issue. Also, your custom pipeline processors may not be triggered as SXA pipeline processors override them. So here are the steps to achieve in a SXA enabled Sitecore site.
- Raise a flag stating its a 404 request.
- Add a new processor to set the HttpStatuscode to 404 and Context item to error page
- Reset the context item
Note: SXA provides the namespace 'Sitecore.XA.Feature.ErrorHandling' with all the error handling implementations. Peeping into this namespace and its code will give you the details on how the ootb errors handlers are implemented. Also, most of the code examples I have provided are inspired from this namespace. So please have a deeper look into it on any similar implementations.
1. Raising & handling custom 404 errors
There could be multiple cases where you might need to show a 404 page content. In my case, I need to return a 404 error page content when ever there is no version in a particular language with language fallback disbled. I have used the 'GetLanguageFallbackItem' to do this. When ever I need to raise a 404 error, I just set the following flag to true.
Sitecore.Context.Items[Constants.NeedsRedirect] = true;
Next, I will check if this flag is set to true in another pipeline processor and show custom 404 error page content. Below is the implementation of the same.
2. Setting 404 HttpStatuscode & redirecting to 404 error page
public class ItemNotFoundResolver: HttpRequestProcessor
{
protected IContext Context { get; } = ServiceLocator.ServiceProvider.GetService();
protected IErrorPageLinkProvider ErrorPageLinkProvider { get; } = ServiceLocator.ServiceProvider.GetService();
public override void Process(HttpRequestArgs args)
{
if(Sitecore.Context.Items.Contains(Constants.NeedsRedirect))
{
RedirectToErrorPageIfExist(args);
}
}
protected void RedirectToErrorPageIfExist(HttpRequestArgs args)
{
if (Settings.RequestErrors.UseServerSideRedirect)
{
Sitecore.Data.Items.Item item = ErrorPageLinkProvider.Get404ErrorPageItem();
if (item != null)
{
args.ProcessorItem = item;
Context.Item = item;
Context.Items["httpStatus"] = HttpStatusCode.NotFound;
args.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
else
{
string text = ErrorPageLinkProvider.Get404ErrorPageUrl();
if (!string.IsNullOrEmpty(text))
{
args.HttpContext.Response.Redirect(text);
}
}
}
}
This needs to be patched after the SXA processor Sitecore.XA.Feature.ErrorHandling.Pipelines.HttpRequestBegin.ItemNotFoundResolver.
3. Setting 404 error page as context item
The Context item set in the above processor will be reset to the original context item in the pipeline
public class CustomErrorPageItem : GetPageItemProcessor
{
protected IContext Context { get; } = ServiceLocator.ServiceProvider.GetService();
public GetCustomErrorPageContextItem(BaseClient baseClient) : base(baseClient)
{
}
public override void Process(GetPageItemArgs args)
{
if (AbortProcessor(args)) return;
args.Result = Context.Item;
}
private bool AbortProcessor(GetPageItemArgs args)
{
if (!Context.Items.Contains(Constants.NeedsRedirect)) return true;
if (Context.Item == null) return true;
if (args.Result != null) return true;
return false;
}
}
This needs to be patched before the Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromRouteUrl
I hope this helps. Please do comment if you have questions.