ASP.NETでHTTP 404「The resource cannot be found.」が出る原因と対処法:Receipt.aspxが表示されない時のIIS/ルーティング完全ガイド

ASP.NETのWebアプリで「Server Error in ‘/’ Application – HTTP 404. The resource cannot be found.」が出ると、原因が見えづらく復旧に時間がかかりがちです。本記事では Teacher/Receipt.aspx?ReferenceNo=... を例に、IIS/ルーティング/配置の各層で起こり得る理由を網羅し、すぐ試せる具体的な確認方法と修正例、再発防止までを実務目線で整理します。

目次

HTTP 404の正体を最初に押さえる

HTTP 404 は「サーバーには到達したが、要求されたリソースが見つからない」ことを示すクライアント向けのステータスです。ASP.NET の場合、物理ファイルが無いルートに一致しないIIS のハンドラ/モジュールが遮断、あるいはアプリ側が意図して 404 を返す(例:存在しない ReferenceNo)のいずれかに大別できます。まずは IIS のサブステータスで、どの層で弾かれているのかを素早く当てます。

IIS 404 サブステータス早見表

sc-status.sc-substatusおおよその意味見るべき場所
404.0一般的な 404(物理パス不在・ルート未一致・アプリからの 404 含む)物理ファイル/ルーティング/アプリログ
404.2ISAPI/CGI 制限などのポリシーで拒否IIS「ISAPI/CGI の制限」
404.3MIME マップ不備(拡張子のハンドラが無い)IIS「ハンドラマッピング」
404.5URL に禁止された文字列Request Filtering
404.7拡張子が Request Filtering で拒否web.config の <requestFiltering>
404.11二重エンコードの拒否などRequest Filtering の設定

まず潰す:7つの即効チェック

調査ポイント具体的な確認・対処方法
URL 誤記パス/拡張子/クエリ文字列のタイポを再確認。Receipt.aspxReceipts.aspx の取り違え、Teacher フォルダ階層を誤っていないか。ブックマークや外部リンクはコピー&ペーストで検証。
物理ファイル・配置Teacher/Receipt.aspx が発行先に存在するか。Web アプリケーションなら .aspx は「ビルド アクション: Content」でプロジェクトに含める。発行プロファイルで「発行時に事前に削除」が有効だと古いファイルが消えるので注意。
ルーティング設定MVC/Web API/WebForms Friendly URLs を使用しているなら、Teacher/Receipt または Teacher/Receipt.aspx にマッチするルートがあるか。レガシーURL救済用のルートを追加。
実行時 404(データ欠損)ReferenceNo が DB に無い場合に、アプリが Response.StatusCode=404 を返していないか。該当コードにログを追加して真因を識別。
誤ったサーバー/サイトIIS 複数サイト/スロット構成で、意図したサイトにデプロイされたか。バインドのホスト名・ポート・SNI を再確認。
IIS 設定.aspx を処理するハンドラ(PageHandlerFactory)が有効か。<modules> の認証モジュールで 404 化していないか。IIS ログでサブステータスを確認。
デバッグ支援web.config<customErrors mode="Off"/><compilation debug="true"/> を一時設定。ブラウザの Network タブや Fiddler で実ステータスと本文を確認。

ケース別:原因と具体的な直し方

1) WebForms(.aspx)ページが見つからない/処理されない

物理ファイルの有無をまず確定する

  • IIS マネージャーでサイトを右クリック → エクスプローラーTeacher/Receipt.aspx の実在を確認。
  • 発行元プロジェクトで Receipt.aspx の「ビルド アクション: Content」「出力ディレクトリにコピー: しない(通常で可)」を確認。プロジェクトに未包含だと発行されません。
  • プリコンパイル発行を使用する場合は「この事前コンパイル済みサイトを更新可能にする」を有効にしないと、.aspx が物理的に無く .compiled のみになる構成もあります。構成に応じて発行手法を統一。

.aspx を処理するハンドラが生きているか

IIS の「ハンドラ マッピング」で PageHandlerFactory-Integrated(パス *.aspx)が「有効」になっているか確認。無効化/削除されていると 404.3/404.7 になり得ます。web.config 側で誤って上書きしていないかも点検します。

&lt;configuration&gt;
  &lt;system.webServer&gt;
    &lt;handlers&gt;
      &lt;add name="PageHandlerFactory-Integrated"
           path="*.aspx"
           verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
           preCondition="integratedMode"
           type="System.Web.UI.PageHandlerFactory" /&gt;
    &lt;/handlers&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;

Request Filtering(要求フィルタ)の拒否を解除

URL に禁止文字や二重エンコードがあると 404.5/404.11 が返ります。今回の例の ReferenceNo=D170102432 は安全ですが、別画面から遷移する際に %2f 等が混入するとブロック対象です。必要に応じて以下のように緩和します。

&lt;configuration&gt;
  &lt;system.webServer&gt;
    &lt;security&gt;
      &lt;requestFiltering allowDoubleEscaping="true"&gt;
        &lt;requestLimits maxQueryString="4096" /&gt;
        &lt;fileExtensions&gt;
          &lt;remove fileExtension=".aspx" /&gt;
          &lt;add fileExtension=".aspx" allowed="true" /&gt;
        &lt;/fileExtensions&gt;
      &lt;/requestFiltering&gt;
    &lt;/security&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;

ページ自体は存在するが、アプリが 404 を返す

「ページはあるのに 404」は、アプリコードでデータ未検出時に 404 を明示している典型例です。調査のため、取得ロジック直後にログを入れて真因を確定します。

&lt;%@ Page Language="C#" Inherits="WebApp.Teacher.Receipt" %&gt;
&lt;script runat="server"&gt;
protected void Page_Load(object sender, EventArgs e)
{
    var referenceNo = Request.QueryString["ReferenceNo"];
    Log.Info($"Receipt.aspx hit: ReferenceNo={referenceNo}");

    var model = Repository.GetReceipt(referenceNo);

    if (model == null)
    {
        // ここで 404 を返している可能性
        Response.StatusCode = 404;
        Response.TrySkipIisCustomErrors = true; // IIS 側の既定 404 に置き換えられないように
        Response.Write("レシートが見つかりません。ReferenceNo=" + Server.HtmlEncode(referenceNo));
        Response.End();
        return;
    }

    // 通常描画...
}
&lt;/script&gt;

要件次第では、404 ではなく「結果 0 件」の専用画面を 200 で返す方がユーザビリティは高まります。

2) MVC/Web API で .aspx URL にアクセスしている

アプリが MVC 化されていて、外部の古いリンクが Receipt.aspx を指しているケースでは「ルート未一致の 404」が起きます。レガシー URL を受け止めるルートを 1 行追加すれば解決します。

// RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    // 旧URL: /Teacher/Receipt.aspx?ReferenceNo=123 を救済
    routes.MapRoute(
        name: "LegacyReceiptAspx",
        url: "Teacher/Receipt.aspx",
        defaults: new { controller = "Teacher", action = "Receipt" }
    );

    // 現行URL: /Teacher/Receipt?ReferenceNo=...
    routes.MapRoute(
        name: "Receipt",
        url: "Teacher/Receipt",
        defaults: new { controller = "Teacher", action = "Receipt" }
    );

    // 既定
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

属性ルーティング派ならアクション側に直接付与します。

public class TeacherController : Controller
{
    [HttpGet]
    [Route("Teacher/Receipt")]
    [Route("Teacher/Receipt.aspx")] // レガシー互換
    public ActionResult Receipt(string ReferenceNo)
    {
        if (string.IsNullOrEmpty(ReferenceNo)) return HttpNotFound();

        var vm = service.FindReceipt(ReferenceNo);
        if (vm == null) return HttpNotFound();

        return View(vm);
    }
}

View 側に .aspx を使っていない MVC なら、URL に .aspx を含めない方針に寄せるのが理想です。どうしても外部リンクが変えられないなら、URL Rewriteルートで吸収しましょう。

3) 誤ったサイト/スロットに発行されている

IIS に複数サイト/バインドがある場合、意図と違うサイトにデプロイされると「対象サイトにはファイルが無い=404」です。以下を確認してください。

  • IIS サイトの バインドでホスト名/ポート/SNI 設定が要求に合致するか。
  • リバースプロキシやロードバランサで、別スロットへ振り分けていないか。
  • 発行プロファイルの「発行先 URL」「サイト名」「ユーザー名」がターゲットと一致するか。

ログ&トレースで「どこで」無くなったかを確定

IIS アクセスログを最速で読む

IIS 既定のログは %SystemDrive%\inetpub\logs\LogFiles\W3SVC{ID}\。以下のように cs-uri-stemReceipt.aspx を、cs-uri-queryReferenceNo を検索します。

# 例: PowerShell で Receipt.aspx を含む行を抽出
Get-ChildItem "C:\inetpub\logs\LogFiles\W3SVC*\u_ex*.log" |
  Select-String "Teacher/Receipt.aspx" |
  Select Line | ForEach-Object { $_.Line }

ログの末尾の sc-status(例:404)、sc-substatus(例:3)、sc-win32-status を確認し、前掲の表に当てはめて層を絞ります。

Failed Request Tracing(FREB)で 404 の内部を可視化

  1. IIS マネージャー → サイト選択 → 失敗した要求のトレース → 有効化。
  2. ルールの追加 → ステータスコードに 404、すべての拡張子、すべての動詞。
  3. 再現後、%SystemDrive%\inetpub\logs\FailedReqLogFiles に出力された .xml を開き、どのモジュール(例:RewriteModule、UrlAuthorization)で 404 になったかを特定。

アプリケーションログの仕込み

「実行時 404」切り分けのため、Receipt に到達したこと/入力パラメータ/DB ヒット件数を構造化ログに出しましょう。

// Serilog 例
Log.Information("Receipt request {@payload}", new { ReferenceNo, User = User.Identity.Name });
var model = repo.GetReceipt(ReferenceNo);
Log.Information("Receipt query result {@result}", new { Found = model != null });

配置・ビルドでハマりやすい落とし穴

ファイルが発行されない/消える

  • プロジェクトに .aspx が「含まれていない」(ソリューション エクスプローラー上に薄いアイコン)→ 発行対象に入らない。
  • 発行時「事前に削除」を有効にして一部フォルダを除外指定していない → 想定外の .aspx が消える。
  • CI/CD で dotnet publish/MSBuild パラメータが環境で異なる → 本番だけファイル構成がズレる。

プリコンパイルの理解不足

Web サイトをプリコンパイルすると 更新不可 モードでは .aspx が無く、.compiled に置き換わります。IIS のハンドラや権限設定が「物理 .aspx 前提」だと 404 になります。運用方針に合わせて「更新可能」を選ぶか、IIS 側の設定を合わせましょう。

セキュリティ設定が 404 を装うケース

認証/承認で 401/403 の代わりに 404 を返すポリシーを取っている場合があります(情報漏洩防止)。ログイン未済やロール不一致で Receipt を隠匿していると、ユーザーからは単なる 404 に見えます。web.config の承認設定を点検します。

&lt;configuration&gt;
  &lt;system.web&gt;
    &lt;authorization&gt;
      &lt;deny users="?" /&gt;  &lt;!-- 匿名拒否 --&gt;
      &lt;allow roles="Teachers" /&gt;
      &lt;deny users="*" /&gt;
    &lt;/authorization&gt;
  &lt;/system.web&gt;

  &lt;location path="Teacher/Receipt.aspx"&gt;
    &lt;system.web&gt;
      &lt;authorization&gt;
        &lt;allow users="*" /&gt; &lt;!-- 必要ならここだけ匿名許可 --&gt;
      &lt;/authorization&gt;
    &lt;/system.web&gt;
  &lt;/location&gt;
&lt;/configuration&gt;

具体例で学ぶ:Receipt を確実に表示する最低限の設定

WebForms の最少構成

// Teacher/Receipt.aspx.cs
namespace WebApp.Teacher {
  public partial class Receipt : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {
      var id = Request.QueryString["ReferenceNo"];
      if (string.IsNullOrWhiteSpace(id))
      {
        Response.StatusCode = 400;
        Response.Write("ReferenceNo が未指定です。");
        Response.End();
        return;
      }


  var receipt = Repo.GetReceipt(id);
  if (receipt == null)
  {
    // 404 にするか、404 ではなく「存在しません」画面にするかは要件で決める
    Response.StatusCode = 404;
    Response.TrySkipIisCustomErrors = true;
    Response.Write($"ReferenceNo={Server.HtmlEncode(id)} のレシートは存在しません。");
    Response.End();
    return;
  }

  // ラベル等にバインドして描画…
}


}
} 

MVC でレガシー .aspx URL を受ける

[RoutePrefix("Teacher")]
public class TeacherController : Controller
{
  [HttpGet, Route("Receipt")]
  [HttpGet, Route("Receipt.aspx")] // 旧URL互換
  public ActionResult Receipt(string ReferenceNo)
  {
    if (string.IsNullOrEmpty(ReferenceNo)) return new HttpStatusCodeResult(400);
    var receipt = service.Find(ReferenceNo);
    if (receipt == null) return HttpNotFound();
    return View(receipt);
  }
}

PowerShell/appcmd でサーバー現地調査を加速

ファイルの存在と更新日時を即確認

Test-Path "D:\Sites\YourSite\Teacher\Receipt.aspx"
Get-Item "D:\Sites\YourSite\Teacher\Receipt.aspx" | Select-Object FullName, Length, LastWriteTime

ハンドラマッピングに .aspx があるか

%windir%\system32\inetsrv\appcmd list config "Default Web Site" ^
 -section:system.webServer/handlers /text:*.aspx

Request Filtering の拡張子許可状況

%windir%\system32\inetsrv\appcmd list config "Default Web Site" ^
 -section:system.webServer/security/requestFiltering

ユーザー体験を守る:カスタム 404 と観測性

カスタム 404 ページ(ユーザー向け)

ユーザーには「見つからない」理由と次の行動(トップに戻る、入力を再確認、問い合わせ)を提供しましょう。

&lt;configuration&gt;
  &lt;system.web&gt;
    &lt;customErrors mode="On" defaultRedirect="~/Errors/GeneralError.aspx"&gt;
      &lt;error statusCode="404" redirect="~/Errors/NotFound.aspx"/&gt;
    &lt;/customErrors&gt;
  &lt;/system.web&gt;

  &lt;system.webServer&gt;
    &lt;httpErrors errorMode="DetailedLocalOnly"&gt;
      &lt;remove statusCode="404" /&gt;
      &lt;error statusCode="404" path="/Errors/NotFound.aspx" responseMode="ExecuteURL" /&gt;
    &lt;/httpErrors&gt;
  &lt;/system.webServer&gt;
&lt;/configuration&gt;

開発者向けに 404 情報を残す

  • 404 発生時に URLクエリユーザーリファラ をアプリログへ記録。
  • FREB(404 ルール)を常時オンにせず、発生時だけ有効化できる運用手順を用意。
  • APM(アプリ監視)でコール率や 404 率を可視化し、リリース直後に急増があれば即座に検知。

チェックリスト(現場でそのまま使える)

  • [ ] その URL をコピー&ペーストで再現したか(ブックマーク・外部リンク依存を排除)。
  • [ ] IIS ログで sc-status.sc-substatus を確認し、層(IIS/ルート/アプリ)を特定。
  • [ ] 物理ファイル Teacher/Receipt.aspx の存在、更新日時、アクセス権(IIS AppPool の ID)を確認。
  • [ ] ハンドラマッピングで *.aspx が有効、Request Filtering で拡張子や二重エンコードが拒否されていない。
  • [ ] MVC/Web API を使っているなら、Receipt.aspx を吸収するレガシールートを追加。
  • [ ] アプリ側のロジックで ReferenceNo 未検出時に 404 を返していないかログで確定。
  • [ ] 複数サイト/スロット誤配備を排除(IIS バインド/CD パイプラインの発行先確認)。
  • [ ] 一時的に <customErrors mode="Off">debug="true" で詳細を確認(本番は速やかに戻す)。

原因別:最短修正パターン集

症状最短修正副作用/注意
404.3(MIME/ハンドラ不備)ハンドラに PageHandlerFactory を追加/有効化アプリケーションプールは「統合パイプライン」を想定
404.7(拡張子拒否)<requestFiltering> で .aspx を許可セキュリティレビューで変更を記録
MVC で Receipt.aspx へアクセスレガシールート "Teacher/Receipt.aspx" を追加URL 設計を段階的にモダン化
デプロイ漏れプロジェクトに .aspx を含めて再発行発行前削除の設定に注意
実行時 404(データ未検出)404 ではなく「結果なし」ページに変更、または入力検証の導線追加SEO 的には 404 を維持する設計も一案

よくある落とし穴と対処のディテール

大文字小文字の違い

Windows の NTFS は既定で大文字小文字非区別ですが、ルーティングや外部サービスが区別することがあります。ブックマークや QR による /teacher/receipt.aspx/Teacher/Receipt.aspx の混在は避け、リダイレクトポリシーで正規化しましょう。

URL Rewrite の副作用

美しい URL のための Rewrite ルールが、特定クエリや拡張子で予期せず除外し 404 にする例が多いです。FREB で RewriteModule の各ステップ(Pattern matched / Action)を確認し、Receipt を通す例外ルールを置きます。

&lt;system.webServer&gt;
  &lt;rewrite&gt;
    &lt;rules&gt;
      &lt;rule name="Allow Receipt.aspx" stopProcessing="true"&gt;
        &lt;match url="^Teacher/Receipt\.aspx$" /&gt;
        &lt;action type="None" /&gt;
      &lt;/rule&gt;
      &lt;!-- 既存ルール... --&gt;
    &lt;/rules&gt;
  &lt;/rewrite&gt;
&lt;/system.webServer&gt;

アプリケーション プールの設定

.NET CLR バージョン/32bit 有効化/パイプライン モードの不整合で、ハンドラがロードされず 404 風味になることがあります。統合パイプライン + 対応 CLR を選んでください。

デバッグを早める小技

開発環境だけ詳細エラーを出す web.config 変換

&lt;configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"&gt;
  &lt;system.web xdt:Transform="InsertIfMissing"&gt;
    &lt;customErrors mode="Off" xdt:Transform="SetAttributes" xdt:Locator="Match(mode)"/&gt;
    &lt;compilation debug="true" xdt:Transform="SetAttributes" xdt:Locator="Match(debug)"/&gt;
  &lt;/system.web&gt;
&lt;/configuration&gt;

Network タブでの確認ポイント

  • ステータスが 200 なのに画面が空白 → クライアント側 JS で別問題。
  • 302 → 404 の遷移 → 認証/ルーティングのリダイレクト経由で 404 化。
  • レスポンス本文に「The resource cannot be found.」 → ASP.NET 既定の 404。

再発防止:運用に組み込む 3 つの仕掛け

スモークテストで URL を自動検証

CI/CD に URL チェック(/Teacher/Receipt.aspx、/Teacher/Receipt)を組み込み、200 が返らなければデプロイを失敗させる。バリエーションとして ReferenceNo の存在・非存在ケースで 200/404 の設計通りかも検証しましょう。

リダイレクトとリンク監査

外部に公開済みの .aspx リンクを把握し、恒久的に 301 リダイレクト で新 URL へ案内。アプリ内のリンクは Url.Action 等のヘルパー経由で生成し、手打ち文字列を排除します。

カスタム 404 のログ強化

404 専用ページで リクエスト パスクエリユーザーセッションID を記録し、ダッシュボードで「急増」「特定 URL 偏在」を可視化。外部リンク切れを即座に発見できます。

まとめ:手順通りに潰せば 404 は怖くない

HTTP 404 は「届いているが見つからない」という事実の表明で、IIS 設定ルートアプリロジックのどこかに原因が必ずあります。本稿のチェックリストに沿って、まず サブステータスで層を特定し、物理ファイルハンドラルート実行時 404 の順に潰してください。レガシーな Receipt.aspx へのリンクが残っているなら、互換ルートを 1 本足すだけで一気にユーザー影響を解消できます。最後に、スモークテストとカスタム 404 のログを運用に組み込めば、同種の不具合は早期に検出・修正可能です。

参考:即投入できるテンプレ集

レガシー URL 吸収(MVC)

routes.MapRoute("LegacyReceiptAspx", "Teacher/Receipt.aspx",
    new { controller = "Teacher", action = "Receipt" });

Request Filtering 緩和

<requestFiltering allowDoubleEscaping="true">
  <fileExtensions>
    <add fileExtension=".aspx" allowed="true" />
  </fileExtensions>
</requestFiltering>

カスタム 404

<httpErrors errorMode="DetailedLocalOnly">
  <error statusCode="404" path="/Errors/NotFound.aspx" responseMode="ExecuteURL" />
</httpErrors>

ログ仕込み(最小)

Log.Info("Receipt hit {ReferenceNo}", ReferenceNo ?? "(null)");

スモークテスト例(擬似コード)

// 200 想定
GET /Teacher/Receipt.aspx?ReferenceNo=DUMMY-EXISTS -> assert 200

// 404 想定
GET /Teacher/Receipt.aspx?ReferenceNo=DUMMY-NOT-EXISTS -> assert 404

// 旧URL → 新URL 301
GET /Teacher/Receipt.aspx -> assert 301 Location: /Teacher/Receipt 

最後に:この記事の使い方

現場では「URL 誤記 → 物理ファイル → ハンドラ → ルート → アプリ 404 → 誤配備」の順で確実に切り分けましょう。詰まったら FREB を一度回す。これだけで 404 調査は劇的に短縮できます。

コメント

コメントする

目次