Sitecore の既定の設定では、アイテムにマッピングできないURLがリクエストされたときに302(Found)というステータスコードがブラウザーに返され、Web.config の下記setting で設定されたページにリダイレクトされます。

<setting name="ItemNotFoundUrl" value="/sitecore/service/notfound.aspx"/>

Notfound.aspx はSitecoreのデフォルトのNot Found エラー用ページ で、内部で 404 のステータスコードをブラウザーに返却します。302によるリダイレクトが発生して404エラーのページを表示する動作自体はサイトコア既定の動作です。多くのシステムでもこのような動きをしていると思います。

今回は、302によるリダイレクトを介さずに404エラーのページを直接返す方法をサイトコアで実現する方法を2つ記載します。今回紹介する方法はあくまで1例です。さまざまな方法で404エラーを直接返すお方法を実装することができます。

今回の検証環境は次の通りです。

  • Sitecore CMS 6.6 SP1

1.RequestErrors.UseServerSideRedirectを変更する

302ではなく、いきなり404エラーのステータスコードを返すようにする1つの方法として、Web.configの RequestErrors.UseServerSideRedirect を既定の false から true に変更します。trueに変更することでマッピングが行えないときにリダイレクトではなくサーバーサイドリダイレクト(ASP.NETの HttpServerUtility.Transfer )が発生し、リダイレクトされずに直接 ItemNotFoundUrl で指定したエラーページの内容が表示されるようになります。

ここで注意点があります。ItemNotFoundUrl で指定して入りエラーページのURLが サイトコアで管理しているアイテムのURLの場合、上記 UseServerSideRedirectの方法で対応できません。なぜなら、サーバーサイドリダイレクトは ASP.NET の HttpServerUtility.Transfer メソッドによる転送を行うので、タイミング的にURLのパスからアイテムを解決するパイプラインが実行されないためです。

RequestErrors.UseServierSideRedirect を true にする場合は、 ItemNotFound で指定される URL は実際にサーバー上に存在する aspx ファイルのURLである必要があります

エラーページのアイテムのページにしたい場合は後述する httpRequestBegin パイプラインをカスタマイズして、カスタムパイプラインプロセッサーを実装する必要があります。

2.カスタムパイプラインプロセッサーを使用する

エラーページをアイテムのページにしたい場合は、パイプラインをカスタマイズする必要があります。方法はいくつか考えられますが、今回はURLのパスに対応するアイテムが見つからない場合にコンテキストアイテムをエラー用のアイテムに設定するという方法で対応する例を記載します。エラー用のアイテムにはレイアウト詳細で設定したレイアウト(aspx)で404ステータスコードを返すようにします。

2.1 カスタムパイプラインプロセッサーを実装する

今回は httpRequestBegin プロセッサーを拡張するための NotFoundProcessor というクラスを作成しました。 NotFoundProcessor では、パスにマッピングできるアイテムが見つからなかった場合かつ、Webサイト上に実際に存在する aspx ファイルが見つからなかった場合、エラー用のアイテム( /sitecore/content/home/404 )を使用してページをレンダリングするように設定しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sample
{
    public class NotFoundProcessor : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
    {
        private const string notFoundPath = "/sitecore/content/home/404";
        /// <summary>
        /// URLに対応するアイテムが存在しない場合
        /// </summary>
        /// <param name="args"></param>
        public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
        {
            if (Sitecore.Context.Item != null 
                || Sitecore.Context.Database == null 
                || Sitecore.Context.Site == null)
            {
                // アイテムが見つかっていたり、サイトコアで管理するサイトではない場合処理スキップ
                return;
            }
            if (Sitecore.Context.Page.FilePath.Length > 0)
            {
                // リクエストされたパスに実際のファイルが存在する場合も処理しない
                return;
            }
            // アイテムを返す
            var notFound = Sitecore.Context.Database.GetItem(notFoundPath);
            if (notFound != null)
            {
                Sitecore.Context.Item = notFound;
            }
        }
    }
}

404アイテムのレイアウト詳細で404エラーを返す必要があります。その処理に関しては後述します。

2.2 Web.config の httpRequestBegin パイプラインプロセッサーを修正する

カスタムパイプラインプロセッサーを作成したのでWeb.config のhttpRequsetBegin にプロセッサーを追加します。Web.config の httpRequestBegin パイプラインの定義で、ItemResolver プロセッサーの定義の後に、先ほど作成したNotFoundProcessor の定義を追加します。

        <processor type="Sample.NotFoundProcessor, Sample"/>

上記設定は例です。アセンブリ名や名前空間などは環境ごとに適当な名前に置き換えてください。これでエラー用のアイテムが見つからなかった場合に404アイテムのページが表示されるようになります。

 

2.3 レイアウトファイルを作成する

404エラー用のページをレンダリングするときに404(Not Found)ステータスコードを返す必要があります。今回はエラーコードを返すために次のような簡単なレイアウト定義アイテムをNotFoundLayoutという名前で作成しました。aspx自体は非常に単純です。ページをレンダリングする際に もともとリクエストされたパスを出力するためのLiteral コントロールと 404 アイテムの Title フィールドをレンダリングするようの FieldRenderer コントロールが配置されています。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="NotFoundLayout.aspx.cs"
    Inherits="Sample.Web.layouts.NotFoundLayout" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <sc:visitoridentification runat="server" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        Request URL:<asp:Literal runat="server" ID="Literal1"></asp:Literal><br />
        <sc:FieldRenderer runat="server" FieldName="Title"></sc:FieldRenderer>
    </div>
    </form>
</body>
</html>

作成した NotFoundLayout.aspxのコードビハインドファイルを次のように実装しています。コードビハインドファイル自体も非常に単純です。リクエストされたURLの出力と404のステータスコードの設定をResponse に設定しています。IISでのエラー処理が動作しないように TrySkipIisCustomErrors を true にしています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Sample.Web.layouts
{
    public partial class NotFoundLayout : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Literal1.Text = Sitecore.Context.RawUrl;
                this.Response.TrySkipIisCustomErrors = true;
                this.Response.StatusDescription = "Page Not Found";
                this.Response.StatusCode = 404;
            }
        }
    }
}

作成したレイアウトをエラーページ用の404アイテムのレイアウト詳細に設定します。今回は次のようにNotFoundLayout を設定しました。

以上で準備完了です。

2.4.動作確認

早速動作確認してみます。外部公開用のサイトをブラウザーで表示して、 存在しないアイテムのパスを指定すると次のように 404アイテムのページが表示されます。ステータスコードは開発者ツールを表示してネットワークの通信をキャプチャして確認できます。

3.まとめ

簡単ですが、302のリダイレクトを介さずに404エラーのステータスを返す方法をご紹介しました。いずれの方法でもブラウザーによるエラーページへのリダイレクトが発生しなくなるのでブラウザー上のアドレスはエラーページのアドレスにならないことに注意してください。