ASP.NET Core の URL リライト ミドルウェア

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

作成者: Kirk LarkinRick Anderson

この記事では、ASP.NET Core アプリの URL リライト ミドルウェアを使用して URL を書き換える手順について説明します。

URL の書き換えは、1 つまたは複数の事前定義された規則に基づいて URL 要求を変更する操作です。 URL 書き換えは、リソースの場所とそれらのアドレスの間の抽象化を作成し、場所とアドレスが緊密にリンクされていないようにします。 URL 書き換えは複数のシナリオで使用できます。

  • サーバー リソースを一時的または永続的に移動するか置き換えて、リソースに対する安定したロケーターを維持します。
  • 要求処理を異なる複数のアプリまたは 1 つのアプリの複数の区分に分割します。
  • 受信した要求の URL セグメントを削除、追加、または再編成します。
  • 検索エンジン最適化 (SEO) のためにパブリック URL を最適化します。
  • ビジターがリソースの要求から返される内容を予測しやすいように、フレンドリなパブリック URL の使用を許可します。
  • セキュリティで保護されていない要求をセキュリティで保護されたエンドポイントにリダイレクトします。
  • 外部サイトが別のサイトでホストされている静的資産を独自のコンテンツにリンクすることによってその資産を使用するホットリンクを防止します。

"URL の書き換えによってアプリのパフォーマンスが低下することがあります"。 ルールの複雑さと数を制限します。

URL リダイレクトと URL 書き換え

"URL リダイレクト" と "URL 書き換え" では表現上はあまり違いがないように見えますが、クライアントへのリソースの提供に関しては重要な意味を持っています。 ASP.NET Core の URL リライト ミドルウェアは、両方のニーズを満たすことができます。

"URL リダイレクト" にはクライアント側の操作が関係しており、クライアントはもともと要求したものとは異なるアドレスにあるリソースにアクセスするよう指示されます。 これによりサーバーへのラウンドトリップが必要になります。 クライアントが、リソースの新しい要求を実行するときに、クライアントに返されたリダイレクト URL がブラウザーのアドレス バーに表示されます。

/resource/different-resource に "リダイレクトされる" 場合、サーバーからの応答では、クライアントが /different-resource にあるリソースを取得する必要があることと、リダイレクトが一時的または永続的のどちらかを示す状態コードが示されます。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に一時的に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求を実行します。サーバーでは、バージョン 2/v2/api のサービスの新しい一時的なパスを使用して 302 (検出) 応答を返します。クライアントでは、リダイレクト URL のサービスに対して 2 回目の要求を実行します。サーバーでは、200 (OK) 状態コードで応答します。

要求を別の URL にリダイレクトする場合は、応答で状態コードを指定することにより、リダイレクトが永続的か一時的かのどちらかを示します。

  • 301 - Moved Permanently 状態コードは、リソースに新しい永続的な URL があり、リソースに対する将来のすべての要求で新しい URL を使用する必要がある場合に使用します。 "301 状態コードを受信すると、クライアントは応答をキャッシュに入れて再利用することができます。 "

  • "302 - Found" 状態コードは、リダイレクトが一時的である場合、または一般に変更される可能性がある場合に使用されます。 302 状態コードは、URL を保存して後で再利用しないようクライアントに指示します。

状態コードについて詳しくは、RFC 9110: 状態コードの定義に関するページを参照してください。

"URL 書き換え" はサーバー側の操作であり、クライアントが要求したものとは異なるリソース アドレスからリソースが提供されます。 URL 書き換えでは、サーバーへのラウンドトリップは必要ありません。 書き換えられた URL は、クライアントに返されず、ブラウザーのアドレス バーに表示されません。

/resource/different-resource に "書き換えられた" 場合、サーバーは /different-resource にあるリソースを "内部的に" 取得して返します。

クライアントは、書き換えられた URL にあるリソースを取得できる場合がありますが、クライアントは、その要求を実行して応答を受信したときに、書き換えられた URL にリソースが存在することは通知されません。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求が実行します。要求 URL は、バージョン 2 パス/v2/api でサービスにアクセスするように再度書き込まれます。サービスは、クライアントに対して 200 (OK) 状態コードで応答します。

URL リライト サンプル アプリ

サンプル アプリを使用して、URL リライト ミドルウェアの機能を調べます。 そのアプリは、リダイレクトと書き換えのルールを適用し、複数のシナリオについて、リダイレクトされた URL または書き換えられた URL を表示します。

URL リライト ミドルウェアを使用する状況

以下の方法では要件が満たされない場合に、URL リライト ミドルウェアを使用します。

アプリが HTTP.sys サーバーでホストされている場合は、URL リライト ミドルウェアを使用します。

IIS、Apache、Nginx でサーバー ベースの URL 書き換えテクノロジが使用される主な理由は次のとおりです。

  • ミドルウェアでは、これらのモジュールの完全な機能がサポートされていません。

    IIS 書き換えモジュールの IsFile 制約や IsDirectory 制約など、サーバー モジュールの一部の機能は、ASP.NET Core プロジェクトでは動作しません。 これらのシナリオでは、代わりにミドルウェアを使用します。

  • 通常、ミドルウェアのパフォーマンスはモジュールより劣ります。

    どちらのアプローチの方がパフォーマンスの低下が大きいか、またはパフォーマンスが低下した場合でもごくわずかかどうかを確実に知るには、ベンチマークが唯一の方法です。

拡張機能とオプション

各書き換えルールに対する拡張メソッドを含む RewriteOptions クラスのインスタンスを作成することにより、URL 書き換えとリダイレクトのルールを設定します。 "処理する順序で" 複数のルールを連結します。 UseRewriter によって URL リライト ミドルウェアが要求パイプラインに追加されると、RewriteOptions が渡されます。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

上記のコードでは、MethodRules はユーザー定義クラスです。 詳細については、この記事の RewriteRules.cs を参照してください。

非 WWW を WWW にリダイレクトする

アプリで非 www の要求を www にリダイレクトできる 3 つのオプションがあります。

  • AddRedirectToWwwPermanent:要求が非 www の場合、要求を www サブドメインに永続的にリダイレクトします。 Status308PermanentRedirect 状態コードでリダイレクトします。

  • AddRedirectToWww:受信した要求が非 www の場合、要求を www サブドメインにリダイレクトします。 Status307TemporaryRedirect 状態コードでリダイレクトします。 オーバーロードにより、応答に対する状態コードを提供することができます。 状態コードの割り当てには、StatusCodes クラスのフィールドを使用します。

URL リダイレクト

要求をリダイレクトするには、AddRedirect を使用します。 最初のパラメーターには、着信 URL のパスに一致する .NET 正規表現 (Regex) が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター (存在する場合) は、状態コードを指定します。 状態コードを指定しない場合、状態コードは既定で "302 - 検出" に設定されます。これは、リソースが一時的に移動されるか置き換えられることを示します。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

開発者ツールが有効になっているブラウザーで、パス /redirect-rule/1234/5678 を指定してサンプル アプリに対する要求を実行します。 正規表現が redirect-rule/(.*) の要求のパスに一致し、パスが /redirected/1234/5678 に置き換えられます。 リダイレクト URL が、"302 - 検出" 状態コードでクライアントに返されます。 ブラウザーは、ブラウザーのアドレス バーに表示されるリダイレクト URL に新しい要求を実行します リダイレクト URL にはサンプル アプリに一致するルールがないため、次のようになります。

  • 2 番目の要求は、アプリから 200 - OK 応答を受け取ります。
  • 応答の本文では、リダイレクト URL が示されています。

URL が "リダイレクト" されるときに、サーバーへのラウンドトリップが実行されます。

警告

リダイレクト ルールを設定するときは注意してください。 リダイレクト ルールは、リダイレクト後を含めて、アプリへのすべての要求で評価されます。 "無限" リダイレクトのループが誤って作成されることがよくあります。

かっこ内に含まれる式の一部は、キャプチャ グループと呼ばれます。 式のドット (.) は、どの文字とも一致することを意味します。 アスタリスク (*) は、直前の文字に 0 回以上一致することを示します。 そのため、URL の最後の 2 つのパス セグメント 1234/5678 は、キャプチャ グループ (.*) によってキャプチャされます。 要求 URL で redirect-rule/ の後に指定した任意の値が、この単一のキャプチャ グループによってキャプチャされます。

置換文字列では、キャプチャされたグループがドル記号 ($) を使用して文字列に挿入され、その後にキャプチャのシーケンス番号が続きます。 最初のキャプチャ グループ値は、$1 で取得され、2 番目は $2 で取得され、これらは正規表現内のキャプチャ グループの順序で続行されます。 redirect-rule/(.*) では、リダイレクト ルールの正規表現内に 1 つのキャプチャ グループだけがあるので、置換文字列に 1 つの挿入されたグループ ($1) だけがあります。 ルールが適用されるときに、URL /redirected/1234/5678 になります。

ブラウザー ツールのネットワーク タブで /redirect-rule/1234/5678 を試してみてください。

セキュリティで保護されたエンドポイントへの URL リダイレクト

HTTP 要求を、同じホストとパスに HTTPS プロトコルを使用してリダイレクトするには、AddRedirectToHttps を使用します。 状態コードが指定されていない場合、ミドルウェアは既定で "302 - 検出" に設定します。 ポートが指定されていない場合は、次のようになります。

  • ミドルウェアの既定値 null に設定されます。
  • スキームは https (HTTPS プロトコル) に変更されて、クライアントはポート 443 でリソースにアクセスします。

次の例では、状態コードを 301 - Moved Permanently に設定し、ポートを localhost で Kestrel によって使用される HTTPS ポートに変更する方法を示します。 運用環境では、HTTPS ポートは null 値に設定されます。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

int? localhostHTTPSport = null;
if (app.Environment.IsDevelopment())
{
    localhostHTTPSport = Int32.Parse(Environment.GetEnvironmentVariable(
                   "ASPNETCORE_URLS")!.Split(new Char[] { ':', ';' })[2]);
}

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        // localhostHTTPport not needed for production, used only with localhost.
        .AddRedirectToHttps(301, localhostHTTPSport)
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

セキュリティで保護されていない要求を、セキュリティで保護された HTTPS プロトコル (ポート 443) を使用して同じホストとパスにリダイレクトするには、AddRedirectToHttpsPermanent を使用します。 ミドルウェアによって状態コードが 301 - Moved Permanently に設定されます。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Note

リダイレクト規則を追加せずにセキュリティで保護されたエンドポイントにリダイレクトするときは、HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、HTTPS の適用に関するページをご覧ください。

サンプル アプリは、AddRedirectToHttps または AddRedirectToHttpsPermanent の使用方法が示されています。 http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz でアプリに対してセキュリティ保護されていない HTTP 要求を行います。 localhost を使用して HTTP から HTTPS へのリダイレクトをテストする場合:

  • HTTPS URL とは異なるポートを持つ、HTTP URL を使用します。 HTTP URL は Properties/launchSettings.json ファイルにあります。
  • https://localhost/{port} から s を削除すると失敗します。localhost が HTTPS ポートに対する HTTP に応答しないためです。

次の図は、上記のコードを使用した http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz に対する要求の F12 ブラウザー ツールの図を示しています。

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: HTTPS へのリダイレクトを追加する

URL 書き換え

URL 書き換えのルールを作成するには、AddRewrite を使用します。 最初のパラメーターには、着信 URL のパスに一致する正規表現が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター skipRemainingRules: {true|false} は、現在のルールが適用される場合に追加の書き換えルールをスキップするかどうかをミドルウェアに示します。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

https://redirect6.azurewebsites.net/rewrite-rule/1234/5678 に対する要求を行ってみてください

式の先頭にあるキャレット (^) は、URL パスの先頭からマッチングが開始されることを意味します。

前のリダイレクト ルール redirect-rule/(.*) の例では、正規表現の先頭にキャレット (^) がありません。 したがって、パスの redirect-rule/ の前にどのような文字があっても一致します。

パス 一致したもの
/redirect-rule/1234/5678 はい
/my-cool-redirect-rule/1234/5678 イエス
/anotherredirect-rule/1234/5678 はい

書き換えルール ^rewrite-rule/(\d+)/(\d+) は、rewrite-rule/ で始まる場合のみパスと一致します。 次の表では、一致の違いに注意してください。

パス 一致したもの
/rewrite-rule/1234/5678 はい
/my-cool-rewrite-rule/1234/5678 いいえ
/anotherrewrite-rule/1234/5678 いいえ

式の ^rewrite-rule/ に続く部分に、2 つのキャプチャ グループ (\d+)/(\d+) があります。 \d は、1 桁 (数字) に一致することを示します。 プラス記号 (+) は、直前の 1 つ以上の文字に一致することを意味します。 そのため、URL は、数字とその後に続くスラッシュ、さらにその後に続く別の数字を含んでいる必要があります。 これらのキャプチャ グループが $1 および $2 として書き換えられた URL に挿入されます。 書き換えルールの置換文字列は、クエリ文字列にキャプチャされたグループを配置します。 要求されたパス /rewrite-rule/1234/5678 は、/rewritten?var1=1234&var2=5678 でリソースを返すように書き換えられます。 クエリ文字列が元の要求に存在する場合、URL が書き換えられるときに保持されます。

リソースを返すためのサーバーへのラウンド トリップはありません。 リソースが存在する場合は、取得され、200 - OK 状態コードと共にクライアントに返されます。 クライアントはリダイレクトされていないため、ブラウザーのアドレス バーの URL は変更されません。 クライアントは、URL の書き換え操作がサーバーで発生したことを検出できません。

URL 書き換えとリダイレクトのパフォーマンスに関するヒント

最速の応答を実現するには:

  • 一致する頻度が最も多いルールから一致頻度が最も少ないルールへの順番で書き換えルールを並べ替えます。
  • 式内の照合ルールは計算量が多く、アプリの応答時間が長くなるので、可能な限り skipRemainingRules: true を使用します。 一致が発生し、追加の処理が必要ないときに残りのルールの処理をスキップします。

警告

悪意のあるユーザーがプロセスに高い負荷がかかる入力を RegularExpressions に提供して、サービス拒否攻撃を引き起こす可能性があります。 RegularExpressions を使用する ASP.NET Core フレームワーク API は、タイムアウトを渡します。 たとえば、RedirectRule クラスと RewriteRule クラスは、どちらも 1 秒のタイムアウトを渡します。

Apache mod_rewrite

AddApacheModRewrite を使用して Apache mod_rewrite ルールを適用します。 ルール ファイルがアプリと共に展開されていることを確認します。 mod_rewrite ルールの情報と例については、「Apache mod_rewrite」を参照してください。

ApacheModRewrite.txt ルール ファイルからルールを読み取るには、StreamReader を使用します。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

サンプル アプリは、要求を /apache-mod-rules-redirect/(.\*) から /redirected?id=$1 にリダイレクトします。 応答の状態コードは "302 -検出" です。

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234 に対する要求を行ってみてください

Apache ミドルウェアでは、次の Apache mod_rewrite サーバー変数がサポートされています。

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

IIS URL リライト モジュールのルール

IIS URL リライト モジュールに適用される同じルール セットを使用するには、AddIISUrlRewrite を使用します。 ルール ファイルがアプリと共に展開されていることを確認します。 Windows Server IIS で実行されているときにミドルウェアでアプリの web.config ファイルを使用するように指定しないでください。 IIS を使用する場合、IIS リライト モジュールとの競合を避けるため、これらのルールをアプリの web.config の外部に保存する必要があります。 IIS URL リライト モジュールのルールの詳細と例については、「Using Url Rewrite Module 2.0」(URL リライト モジュール 2.0 の使用 ) と「URL Rewrite Module Configuration Reference」(URL リライト モジュール構成リファレンス) を参照してください。

IISUrlRewrite.xml ルール ファイルからルールを読み取るには、StreamReader を使用します。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

サンプル アプリは、要求を /iis-rules-rewrite/(.*) から /rewritten?id=$1 に書き換えます。 応答は、200 - OK 状態コードでクライアントに送信されます。

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz に対する要求を行ってみてください

アプリでサーバーレベルのルールを含むアクティブな IIS リライト モジュールが構成されていて、望ましくない方法でアプリに影響を与える場合:

  • アプリの IIS リライト モジュールを無効にすることを検討してください。
  • 詳細については、「Disabling IIS modules」 (IIS モジュールの無効化) を参照してください。

サポートされていない機能

ミドルウェアでは、次の IIS URL リライト モジュールの機能がサポートされていません。

  • 送信ルール
  • カスタム サーバー変数
  • ワイルドカード
  • LogRewrittenUrl

サポートされるサーバー変数

ミドルウェアでは、次の IIS URL リライト モジュール サーバー変数がサポートされています。

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

IFileProviderPhysicalFileProvider 経由で取得できます。 このアプローチにより、書き換えルール ファイルの場所に関する柔軟性が向上する場合があります。 書き換えルール ファイルが指定したパスでサーバーに展開されていることを確認してください。

var fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

メソッド ベースのルール

メソッド内でカスタム ルール ロジックを実装するには、Add を使用します。 Add によって RewriteContext が公開され、リダイレクト メソッドで HttpContext を使用できるようになります。 RewriteContext.Result プロパティによって、追加のパイプライン処理の実行方法を決定します。 次の表で説明する RuleResult フィールドのいずれかに値を設定します。

コンテキストの書き換えの結果 アクション
RuleResult.ContinueRules (既定値) ルールの適用を続けます。
RuleResult.EndResponse ルールの適用を停止し、応答を送信します。
RuleResult.SkipRemainingRules ルールの適用を停止し、次のミドルウェアにコンテキストを送信します。
using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

サンプル アプリは、 .xml で終了するパスの要求をリダイレクトするメソッドの例を示します。 /file.xml に対して要求が行われるとき:

  • 要求は /xmlfiles/file.xml にリダイレクトされます
  • 状態コードは 301 - Moved Permanently に設定されます。 ブラウザーが /xmlfiles/file.xml に対する新しい要求を行うと、静的ファイル ミドルウェアはクライアントに wwwroot/xmlfiles フォルダーからファイルを提供します。 リダイレクトの場合は、応答の状態コードを明示的に設定します。 それ以外の場合は、200 - OK 状態コードが返され、クライアントでのリダイレクトは発生しません。

RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")) ||
        request.Path.Value==null)
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

このアプローチでは、要求を書き換えることもできます。 サンプル アプリでは、wwwroot フォルダーから file.txt テキスト ファイルを提供するためにテキスト ファイル要求のパスを書き換える処理が示されています。 静的ファイル ミドルウェアでは、更新された要求パスに基づいてファイルが提供されます。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

RewriteRules.cs:

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value != null &&
        request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

IRule ベースのルール

IRule インターフェイスを実装するクラス内のルール ロジックを使用するには、Add を使用します。 IRule では、メソッド ベースのルール アプローチを使用する場合より高い柔軟性が提供されます。 実装クラスには、ApplyRule メソッドに対してパラメーターを渡すことができるコンストラクターを含めることができます。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

サンプル アプリの extensionnewPath のパラメーターの値は、いくつかの条件を満たすかチェックされます。 extension は値を含んでいる必要があり、その値は .png.jpg、または .gif でなければなりません。 newPath が有効ではない場合、ArgumentException がスローされます。 image.png に対して要求が行われた場合、要求は /png-images/image.png にリダイレクトされます。 image.jpg に対して要求が行われた場合、要求は /jpg-images/image.jpg にリダイレクトされます。 状態コードは 301 - Moved Permanently に設定され、context.Result はルールの処理を停止して応答を送信するように設定されます。

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)) ||
            request.Path.Value == null)
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

次のメソッドを試してください。

  • PNG 要求: https://redirect6.azurewebsites.net/image.png
  • JPG 要求: https://redirect6.azurewebsites.net/image.jpg

正規表現の例

Goal 正規表現文字列と
一致の例
置換文字列と
出力の例
クエリ文字列内のパスを書き換える ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
末尾のスラッシュを除去する ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
末尾のスラッシュを強制する ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
特定の要求を書き換えを回避する ^(.*)(?<!\.axd)$ または
^(?!.*\.axd$)(.*)$
はい: /path4/resource.htm
いいえ: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
URL セグメントを再配置する path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
URL セグメントを置き換える ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

上記の表のリンクでは、Azure にデプロイされた次のコードが使用されています。

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)

        // Rewrite path to QS.
        .AddRewrite(@"^path/(.*)/(.*)", "path?var1=$1&var2=$2",
            skipRemainingRules: true)
        // Skip trailing slash.
        .AddRewrite(@"^path2/(.*)/$", "path2/$1",
            skipRemainingRules: true)
         // Enforce trailing slash.
         .AddRewrite(@"^path3/(.*[^/])$", "path3/$1/",
            skipRemainingRules: true)
         // Avoid rewriting specific requests.
         .AddRewrite(@"^path4/(.*)(?<!\.axd)$", "rewritten/$1",
            skipRemainingRules: true)
         // Rearrange URL segments
         .AddRewrite(@"^path5/(.*)/(.*)/(.*)", "path5/$3/$2/$1",
            skipRemainingRules: true)
          // Replace a URL segment
          .AddRewrite(@"^path6/(.*)/segment2/(.*)", "path6/$1/replaced/$2",
            skipRemainingRules: true)

        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

上記の正規表現サンプルのほとんどでは、リテラル path を使って、デプロイされたサンプルに対する一意のテスト可能な書き換えルールを作成しています。 通常、正規表現には path は含まれません。 たとえば、こちらの正規表現の例の表を参照してください。

このドキュメントでは、ASP.NET Core アプリの URL リライト ミドルウェアを使用して URL を書き換える手順について説明します。

URL の書き換えは、1 つまたは複数の事前定義された規則に基づいて URL 要求を変更する操作です。 URL 書き換えは、リソースの場所とそれらのアドレスの間の抽象化を作成し、場所とアドレスが緊密にリンクされていないようにします。 URL 書き換えは複数のシナリオで使用できます。

  • サーバー リソースを一時的または永続的に移動するか置き換えて、リソースに対する安定したロケーターを維持します。
  • 要求処理を異なる複数のアプリまたは 1 つのアプリの複数の区分に分割します。
  • 受信した要求の URL セグメントを削除、追加、または再編成します。
  • 検索エンジン最適化 (SEO) のためにパブリック URL を最適化します。
  • ビジターがリソースの要求から返される内容を予測しやすいように、フレンドリなパブリック URL の使用を許可します。
  • セキュリティで保護されていない要求をセキュリティで保護されたエンドポイントにリダイレクトします。
  • 外部サイトが別のサイトでホストされている静的資産を独自のコンテンツにリンクすることによってその資産を使用するホットリンクを防止します。

Note

URL の書き換えによってアプリのパフォーマンスが低下することがあります。 可能であれば、ルールの複雑さと数を制限します。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

URL リダイレクトと URL 書き換え

"URL リダイレクト" と "URL 書き換え" では表現上はあまり違いがないように見えますが、クライアントへのリソースの提供に関しては重要な意味を持っています。 ASP.NET Core の URL リライト ミドルウェアは、両方のニーズを満たすことができます。

"URL リダイレクト" にはクライアント側の操作が関係しており、クライアントはもともと要求したものとは異なるアドレスにあるリソースにアクセスするよう指示されます。 これによりサーバーへのラウンドトリップが必要になります。 クライアントが、リソースの新しい要求を実行するときに、クライアントに返されたリダイレクト URL がブラウザーのアドレス バーに表示されます。

/resource/different-resource に "リダイレクトされる" 場合、サーバーからの応答では、クライアントが /different-resource にあるリソースを取得する必要があることと、リダイレクトが一時的または永続的のどちらかを示す状態コードが示されます。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に一時的に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求を実行します。サーバーでは、バージョン 2/v2/api のサービスの新しい一時的なパスを使用して 302 (検出) 応答を返します。クライアントでは、リダイレクト URL のサービスに対して 2 回目の要求を実行します。サーバーでは、200 (OK) 状態コードで応答します。

要求を別の URL にリダイレクトする場合は、応答で状態コードを指定することにより、リダイレクトが永続的か一時的かのどちらかを示します。

  • 301 - Moved Permanently 状態コードは、リソースに新しい永続的な URL があり、リソースに対する将来のすべての要求で新しい URL を使用する必要があることをクライアントに指示したい場合に使用します。 "301 状態コードを受信すると、クライアントは応答をキャッシュに入れて再利用することができます。 "

  • "302 - 検出" 状態コードは、リダイレクトが一時的である場合、または一般に変更される可能性がある場合に使用されます。 302 状態コードは、URL を保存して後で再利用しないようクライアントに指示します。

状態コードについて詳しくは、RFC 9110: 状態コードの定義に関するページを参照してください。

"URL 書き換え" はサーバー側の操作であり、クライアントが要求したものとは異なるリソース アドレスからリソースが提供されます。 URL 書き換えでは、サーバーへのラウンドトリップは必要ありません。 書き換えられた URL は、クライアントに返されず、ブラウザーのアドレス バーに表示されません。

/resource/different-resource に "書き換えられた" 場合、サーバーは /different-resource にあるリソースを "内部的に" 取得して返します。

クライアントは、書き換えられた URL にあるリソースを取得できる場合がありますが、クライアントは、その要求を実行して応答を受信したときに、書き換えられた URL にリソースが存在することは通知されません。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求が実行します。要求 URL は、バージョン 2 パス/v2/api でサービスにアクセスするように再度書き込まれます。サービスは、クライアントに対して 200 (OK) 状態コードで応答します。

URL リライト サンプル アプリ

サンプル アプリを使用して、URL リライト ミドルウェアの機能を調べることができます。 そのアプリは、リダイレクトと書き換えのルールを適用し、複数のシナリオについて、リダイレクトされた URL または書き換えられた URL を表示します。

URL リライト ミドルウェアを使用する状況

次の方法を使用できない場合は、URL リライト ミドルウェアを使用します。

アプリが HTTP.sys サーバーでホストされている場合は、URL リライト ミドルウェアを使用します。

IIS、Apache、Nginx でサーバー ベースの URL 書き換えテクノロジが使用される主な理由は次のとおりです。

  • ミドルウェアでは、これらのモジュールの完全な機能がサポートされていません。

    IIS 書き換えモジュールの IsFile 制約や IsDirectory 制約など、サーバー モジュールの一部の機能は、ASP.NET Core プロジェクトでは動作しません。 これらのシナリオでは、代わりにミドルウェアを使用します。

  • 通常、ミドルウェアのパフォーマンスはモジュールより劣ります。

    どちらのアプローチの方がパフォーマンスの低下が大きいか、またはパフォーマンスが低下した場合でもごくわずかかどうかを確実に知るには、ベンチマークが唯一の方法です。

Package

URL リライト ミドルウェアは、Microsoft.AspNetCore.Rewrite パッケージによって提供されます。このパッケージは ASP.NET Core アプリに暗黙的に含まれています。

拡張機能とオプション

各書き換えルールに対する拡張メソッドを含む RewriteOptions クラスのインスタンスを作成することにより、URL 書き換えとリダイレクトのルールを設定します。 処理したい順序で複数のルールを連結します。 UseRewriter によって URL リライト ミドルウェアが要求パイプラインに追加されると、RewriteOptions が渡されます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

非 WWW を WWW にリダイレクトする

アプリで非 www の要求を www にリダイレクトできる 3 つのオプションがあります。

  • AddRedirectToWwwPermanent:要求が非 www の場合、要求を www サブドメインに永続的にリダイレクトします。 Status308PermanentRedirect 状態コードでリダイレクトします。

  • AddRedirectToWww:受信した要求が非 www の場合、要求を www サブドメインにリダイレクトします。 Status307TemporaryRedirect 状態コードでリダイレクトします。 オーバーロードにより、応答に対する状態コードを提供することができます。 状態コードの割り当てには、StatusCodes クラスのフィールドを使用します。

URL リダイレクト

要求をリダイレクトするには、AddRedirect を使用します。 最初のパラメーターには、着信 URL のパスに一致する正規表現が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター (存在する場合) は、状態コードを指定します。 状態コードを指定しない場合、状態コードは既定で "302 - 検出" に設定されます。これは、リソースが一時的に移動されるか置き換えられることを示します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

開発者ツールが有効になっているブラウザーで、パス /redirect-rule/1234/5678 を指定してサンプル アプリに対する要求を実行します。 正規表現が redirect-rule/(.*) の要求のパスに一致し、パスが /redirected/1234/5678 に置き換えられます。 リダイレクト URL が、"302 - 検出" 状態コードでクライアントに返されます。 ブラウザーは、ブラウザーのアドレス バーに表示されるリダイレクト URL に新しい要求を実行します リダイレクト URL にはサンプル アプリに一致するルールがないため、次のようになります。

  • 2 番目の要求は、アプリから 200 - OK 応答を受け取ります。
  • 応答の本文では、リダイレクト URL が示されています。

URL が "リダイレクト" されるときに、サーバーへのラウンドトリップが実行されます。

警告

リダイレクト ルールを設定するときは注意してください。 リダイレクト ルールは、リダイレクト後を含めて、アプリへのすべての要求で評価されます。 "無限リダイレクトのループ" が誤って作成されることがよくあります。

元の要求: /redirect-rule/1234/5678

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: リダイレクトを追加する

かっこ内に含まれる式の一部は、キャプチャ グループと呼ばれます。 式のドット (.) は、どの文字とも一致することを意味します。 アスタリスク (*) は、直前の文字に 0 回以上一致することを示します。 そのため、URL の最後の 2 つのパス セグメント 1234/5678 は、キャプチャ グループ (.*) によってキャプチャされます。 要求 URL で redirect-rule/ の後に指定した任意の値が、この単一のキャプチャ グループによってキャプチャされます。

置換文字列では、キャプチャされたグループがドル記号 ($) を使用して文字列に挿入され、その後にキャプチャのシーケンス番号が続きます。 最初のキャプチャ グループ値は、$1 で取得され、2 番目は $2 で取得され、これらは正規表現内のキャプチャ グループの順序で続行されます。 サンプル アプリでは、リダイレクト ルールの正規表現内に 1 つのキャプチャ グループだけがあるので、置換文字列に 1 つの挿入されたグループ ($1) だけがあります。 ルールが適用されるときに、URL /redirected/1234/5678 になります。

セキュリティで保護されたエンドポイントへの URL リダイレクト

HTTP 要求を、同じホストとパスに HTTPS プロトコルを使用してリダイレクトするには、AddRedirectToHttps を使用します。 状態コードが指定されていない場合、ミドルウェアは既定で "302 - 検出" に設定します。 ポートが指定されていない場合は、次のようになります。

  • ミドルウェアの既定値 null に設定されます。
  • スキームは https (HTTPS プロトコル) に変更されて、クライアントはポート 443 でリソースにアクセスします。

次の例では、状態コードを "301 - Moved Permanently" に設定し、ポートを 5001 に変更する方法を示します。

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

セキュリティで保護されていない要求を、セキュリティで保護された HTTPS プロトコル (ポート 443) を使用して同じホストとパスにリダイレクトするには、AddRedirectToHttpsPermanent を使用します。 ミドルウェアによって状態コードが 301 - Moved Permanently に設定されます。

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

Note

リダイレクト規則を追加せずにセキュリティで保護されたエンドポイントにリダイレクトするときは、HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、「HTTPS の適用」のトピックをご覧ください。

サンプル アプリは、AddRedirectToHttps または AddRedirectToHttpsPermanent の使用方法の例を示すことができます。 拡張メソッドを RewriteOptions に追加します。 任意の URL でセキュリティ保護されていない要求をアプリに対して行います。 自己署名証明書が信頼できないことを示すブラウザーのセキュリティ警告を消去するか、証明書を信頼する例外を作成します。

AddRedirectToHttps(301, 5001): http://localhost:5000/secure を使用する元の要求

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: HTTPS へのリダイレクトを追加する

AddRedirectToHttpsPermanent: http://localhost:5000/secure を使用する元の要求

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: HTTPS へのリダイレクト (永続) を追加する

URL 書き換え

URL 書き換えのルールを作成するには、AddRewrite を使用します。 最初のパラメーターには、着信 URL のパスに一致する正規表現が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター skipRemainingRules: {true|false} は、現在のルールが適用される場合に追加の書き換えルールをスキップするかどうかをミドルウェアに示します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

元の要求: /rewrite-rule/1234/5678

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: 書き換えを追加する

式の先頭にあるキャレット (^) は、URL パスの先頭からマッチングが開始されることを意味します。

前のリダイレクト ルール redirect-rule/(.*) の例では、正規表現の先頭にキャレット (^) がありません。 したがって、パスの redirect-rule/ の前にどのような文字があっても一致します。

パス 一致したもの
/redirect-rule/1234/5678 はい
/my-cool-redirect-rule/1234/5678 イエス
/anotherredirect-rule/1234/5678 はい

書き換えルール ^rewrite-rule/(\d+)/(\d+) は、rewrite-rule/ で始まる場合のみパスと一致します。 次の表では、一致の違いに注意してください。

パス 一致したもの
/rewrite-rule/1234/5678 はい
/my-cool-rewrite-rule/1234/5678 いいえ
/anotherrewrite-rule/1234/5678 いいえ

式の ^rewrite-rule/ に続く部分に、2 つのキャプチャ グループ (\d+)/(\d+) があります。 \d は、1 桁 (数字) に一致することを示します。 プラス記号 (+) は、直前の 1 つ以上の文字に一致することを意味します。 そのため、URL は、数字とその後に続くスラッシュ、さらにその後に続く別の数字を含んでいる必要があります。 これらのキャプチャ グループが $1 および $2 として書き換えられた URL に挿入されます。 書き換えルールの置換文字列は、クエリ文字列にキャプチャされたグループを配置します。 /rewrite-rule/1234/5678 の要求されたパスは、/rewritten?var1=1234&var2=5678 でリソースを取得するように書き換えられます。 クエリ文字列が元の要求に存在する場合、URL が書き換えられるときに保持されます。

リソースを取得するためのサーバーへのラウンドトリップはありません。 リソースが存在する場合は、取得され、200 - OK 状態コードと共にクライアントに返されます。 クライアントはリダイレクトされていないため、ブラウザーのアドレス バーの URL は変更されません。 クライアントは、URL の書き換え操作がサーバーで発生したことを検出できません。

Note

式内の照合ルールは計算量が多く、アプリの応答時間が長くなるので、可能な限り skipRemainingRules: true を使用します。 最も高速なアプリの応答を実現するには以下のようにします。

  • 一致する頻度が最も多いルールから一致頻度が最も少ないルールへの順番で書き換えルールを並べ替えます。
  • 一致が発生し、追加の処理が必要ないときに残りのルールの処理をスキップします。

Apache mod_rewrite

AddApacheModRewrite を使用して Apache mod_rewrite ルールを適用します。 ルール ファイルがアプリと共に展開されていることを確認します。 mod_rewrite ルールの情報と例については、「Apache mod_rewrite」を参照してください。

ApacheModRewrite.txt ルール ファイルからルールを読み取るには、StreamReader を使用します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、要求を /apache-mod-rules-redirect/(.\*) から /redirected?id=$1 にリダイレクトします。 応答の状態コードは "302 -検出" です。

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

元の要求: /apache-mod-rules-redirect/1234

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: Apache mod リダイレクトを追加する

ミドルウェアは、次の Apache mod_rewrite サーバー変数をサポートします。

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

IIS URL リライト モジュールのルール

IIS URL リライト モジュールに適用される同じルール セットを使用するには、AddIISUrlRewrite を使用します。 ルール ファイルがアプリと共に展開されていることを確認します。 Windows Server IIS で実行されているときにミドルウェアでアプリの web.config ファイルを使用するように指定しないでください。 IIS を使用する場合、IIS リライト モジュールとの競合を避けるため、これらのルールをアプリの web.config の外部に保存する必要があります。 IIS URL リライト モジュールのルールの詳細と例については、「Using Url Rewrite Module 2.0」(URL リライト モジュール 2.0 の使用 ) と「URL Rewrite Module Configuration Reference」(URL リライト モジュール構成リファレンス) を参照してください。

IISUrlRewrite.xml ルール ファイルからルールを読み取るには、StreamReader を使用します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、要求を /iis-rules-rewrite/(.*) から /rewritten?id=$1 に書き換えます。 応答は、200 - OK 状態コードでクライアントに送信されます。

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

元の要求: /iis-rules-rewrite/1234

要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ: IIS URL 書き換えを追加する

望ましくない方法でアプリに影響するように構成されたサーバー レベル ルールを使用するアクティブな IIS リライト モジュールがある場合は、アプリに対して IIS リライト モジュールを無効にできます。 詳細については、「Disabling IIS modules」 (IIS モジュールの無効化) を参照してください。

サポートされていない機能

ミドルウェアでは、次の IIS URL リライト モジュールの機能がサポートされていません。

  • 送信ルール
  • カスタム サーバー変数
  • ワイルドカード
  • LogRewrittenUrl

サポートされるサーバー変数

ミドルウェアは、次の IIS URL リライト モジュール サーバー変数をサポートします。

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

Note

PhysicalFileProvider を介して IFileProvider を取得することもできます。 このアプローチは、書き換えルール ファイルの場所に関する大きな柔軟性を提供する場合があります。 書き換えルール ファイルを指定したパスでサーバーに導入されていることを確認してください。

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

メソッド ベースのルール

メソッド内で独自のルール ロジックを実装するには、Add を使用します。 AddRewriteContext を公開し、メソッドで HttpContext を使用できるようにします。 RewriteContext.Result は、追加のパイプライン処理の実行方法を決定します。 次の表で説明する RuleResult フィールドのいずれかに値を設定します。

コンテキストの書き換えの結果 アクション
RuleResult.ContinueRules (既定値) ルールの適用を続けます。
RuleResult.EndResponse ルールの適用を停止し、応答を送信します。
RuleResult.SkipRemainingRules ルールの適用を停止し、次のミドルウェアにコンテキストを送信します。
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、 .xml で終了するパスの要求をリダイレクトするメソッドの例を示します。 /file.xml に対して要求が行われた場合、要求は /xmlfiles/file.xml にリダイレクトされます。 状態コードは 301 - Moved Permanently に設定されます。 ブラウザーが /xmlfiles/file.xml に対する新しい要求を行うと、静的ファイル ミドルウェアはクライアントに wwwroot/xmlfiles フォルダーからファイルを提供します。 リダイレクトの場合は、応答の状態コードを明示的に設定します。 それ以外の場合は、200 - OK 状態コードが返され、クライアントでのリダイレクトは発生しません。

RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

このアプローチでは、要求を書き換えることもできます。 サンプル アプリでは、wwwroot フォルダーから file.txt テキスト ファイルを提供するためにテキスト ファイル要求のパスを書き換える処理が示されています。 静的ファイル ミドルウェアでは、更新された要求パスに基づいてファイルが提供されます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs:

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

IRule ベースのルール

IRule インターフェイスを実装するクラス内のルール ロジックを使用するには、Add を使用します。 IRule では、メソッド ベースのルール アプローチを使用する場合より高い柔軟性が提供されます。 実装クラスには、ApplyRule メソッドに対してパラメーターを渡すことができるコンストラクターを含めることができます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリの extensionnewPath のパラメーターの値は、いくつかの条件を満たすかチェックされます。 extension は、値を含んでいる必要があり、値は .png.jpg、または .gif でなければなりません。 newPath が有効ではない場合、ArgumentException がスローされます。 image.png に対して要求が行われた場合、要求は /png-images/image.png にリダイレクトされます。 image.jpg に対して要求が行われた場合、要求は /jpg-images/image.jpg にリダイレクトされます。 状態コードは 301 - Moved Permanently に設定され、context.Result はルールの処理を停止して応答を送信するように設定されます。

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

元の要求: /image.png

image.png の要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

元の要求: /image.jpg

image.jpg の要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

正規表現の例

Goal 正規表現文字列と
一致の例
置換文字列と
出力の例
クエリ文字列内のパスを書き換える ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
末尾のスラッシュを除去する (.*)/$
/path/
$1
/path
末尾のスラッシュを強制する (.*[^/])$
/path
$1/
/path/
特定の要求を書き換えを回避する ^(.*)(?<!\.axd)$ または ^(?!.*\.axd$)(.*)$
はい: /resource.htm
いいえ: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
URL セグメントを再配置する path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
URL セグメントを置き換える ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

このドキュメントでは、ASP.NET Core アプリの URL リライト ミドルウェアを使用して URL を書き換える手順について説明します。

URL の書き換えは、1 つまたは複数の事前定義された規則に基づいて URL 要求を変更する操作です。 URL 書き換えは、リソースの場所とそれらのアドレスの間の抽象化を作成し、場所とアドレスが緊密にリンクされていないようにします。 URL 書き換えは複数のシナリオで使用できます。

  • サーバー リソースを一時的または永続的に移動するか置き換えて、リソースに対する安定したロケーターを維持します。
  • 要求処理を異なる複数のアプリまたは 1 つのアプリの複数の区分に分割します。
  • 受信した要求の URL セグメントを削除、追加、または再編成します。
  • 検索エンジン最適化 (SEO) のためにパブリック URL を最適化します。
  • ビジターがリソースの要求から返される内容を予測しやすいように、フレンドリなパブリック URL の使用を許可します。
  • セキュリティで保護されていない要求をセキュリティで保護されたエンドポイントにリダイレクトします。
  • 外部サイトが別のサイトでホストされている静的資産を独自のコンテンツにリンクすることによってその資産を使用するホットリンクを防止します。

Note

URL の書き換えによってアプリのパフォーマンスが低下することがあります。 可能であれば、ルールの複雑さと数を制限します。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

URL リダイレクトと URL 書き換え

"URL リダイレクト" と "URL 書き換え" では表現上はあまり違いがないように見えますが、クライアントへのリソースの提供に関しては重要な意味を持っています。 ASP.NET Core の URL リライト ミドルウェアは、両方のニーズを満たすことができます。

"URL リダイレクト" にはクライアント側の操作が関係しており、クライアントはもともと要求したものとは異なるアドレスにあるリソースにアクセスするよう指示されます。 これによりサーバーへのラウンドトリップが必要になります。 クライアントが、リソースの新しい要求を実行するときに、クライアントに返されたリダイレクト URL がブラウザーのアドレス バーに表示されます。

/resource/different-resource に "リダイレクトされる" 場合、サーバーからの応答では、クライアントが /different-resource にあるリソースを取得する必要があることと、リダイレクトが一時的または永続的のどちらかを示す状態コードが示されます。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に一時的に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求を実行します。サーバーでは、バージョン 2/v2/api のサービスの新しい一時的なパスを使用して 302 (検出) 応答を返します。クライアントでは、リダイレクト URL のサービスに対して 2 回目の要求を実行します。サーバーでは、200 (OK) 状態コードで応答します。

要求を別の URL にリダイレクトする場合は、応答で状態コードを指定することにより、リダイレクトが永続的か一時的かのどちらかを示します。

  • 301 - Moved Permanently 状態コードは、リソースに新しい永続的な URL があり、リソースに対する将来のすべての要求で新しい URL を使用する必要があることをクライアントに指示したい場合に使用します。 "301 状態コードを受信すると、クライアントは応答をキャッシュに入れて再利用することができます。 "

  • "302 - 検出" 状態コードは、リダイレクトが一時的である場合、または一般に変更される可能性がある場合に使用されます。 302 状態コードは、URL を保存して後で再利用しないようクライアントに指示します。

状態コードについて詳しくは、RFC 9110: 状態コードの定義に関するページを参照してください。

"URL 書き換え" はサーバー側の操作であり、クライアントが要求したものとは異なるリソース アドレスからリソースが提供されます。 URL 書き換えでは、サーバーへのラウンドトリップは必要ありません。 書き換えられた URL は、クライアントに返されず、ブラウザーのアドレス バーに表示されません。

/resource/different-resource に "書き換えられた" 場合、サーバーは /different-resource にあるリソースを "内部的に" 取得して返します。

クライアントは、書き換えられた URL にあるリソースを取得できる場合がありますが、クライアントは、その要求を実行して応答を受信したときに、書き換えられた URL にリソースが存在することは通知されません。

WebAPI サービス エンドポイントは、サーバー上でバージョン 1 (v1) からバージョン 2 (v2) に変更されました。クライアントでは、バージョン 1 パス /v1/api のサービスに対して要求が実行します。要求 URL は、バージョン 2 パス/v2/api でサービスにアクセスするように再度書き込まれます。サービスは、クライアントに対して 200 (OK) 状態コードで応答します。

URL リライト サンプル アプリ

サンプル アプリを使用して、URL リライト ミドルウェアの機能を調べることができます。 そのアプリは、リダイレクトと書き換えのルールを適用し、複数のシナリオについて、リダイレクトされた URL または書き換えられた URL を表示します。

URL リライト ミドルウェアを使用する状況

次の方法を使用できない場合は、URL リライト ミドルウェアを使用します。

また、アプリが HTTP.sys サーバー (旧称 WebListener) でホストされているときも、ミドルウェアを使用します。

IIS、Apache、Nginx でサーバー ベースの URL 書き換えテクノロジが使用される主な理由は次のとおりです。

  • ミドルウェアでは、これらのモジュールの完全な機能がサポートされていません。

    IIS 書き換えモジュールの IsFile 制約や IsDirectory 制約など、サーバー モジュールの一部の機能は、ASP.NET Core プロジェクトでは動作しません。 これらのシナリオでは、代わりにミドルウェアを使用します。

  • 通常、ミドルウェアのパフォーマンスはモジュールより劣ります。

    どちらのアプローチの方がパフォーマンスの低下が大きいか、またはパフォーマンスが低下した場合でもごくわずかかどうかを確実に知るには、ベンチマークが唯一の方法です。

Package

ミドルウェアをプロジェクトに組み込むには、Microsoft.AspNetCore.App メタパッケージへのパッケージ参照をプロジェクト ファイルに追加します。これには、Microsoft.AspNetCore.Rewrite パッケージが含まれます。

Microsoft.AspNetCore.App メタパッケージを使用しない場合は、Microsoft.AspNetCore.Rewrite パッケージへのプロジェクト参照を追加します。

拡張機能とオプション

各書き換えルールに対する拡張メソッドを含む RewriteOptions クラスのインスタンスを作成することにより、URL 書き換えとリダイレクトのルールを設定します。 処理したい順序で複数のルールを連結します。 UseRewriter によって URL リライト ミドルウェアが要求パイプラインに追加されると、RewriteOptions が渡されます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

非 WWW を WWW にリダイレクトする

アプリで非 www の要求を www にリダイレクトできる 3 つのオプションがあります。

  • AddRedirectToWwwPermanent:要求が非 www の場合、要求を www サブドメインに永続的にリダイレクトします。 Status308PermanentRedirect 状態コードでリダイレクトします。

  • AddRedirectToWww:受信した要求が非 www の場合、要求を www サブドメインにリダイレクトします。 Status307TemporaryRedirect 状態コードでリダイレクトします。 オーバーロードにより、応答に対する状態コードを提供することができます。 状態コードの割り当てには、StatusCodes クラスのフィールドを使用します。

URL リダイレクト

要求をリダイレクトするには、AddRedirect を使用します。 最初のパラメーターには、着信 URL のパスに一致する正規表現が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター (存在する場合) は、状態コードを指定します。 状態コードを指定しない場合、状態コードは既定で "302 - 検出" に設定されます。これは、リソースが一時的に移動されるか置き換えられることを示します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

開発者ツールが有効になっているブラウザーで、パス /redirect-rule/1234/5678 を指定してサンプル アプリに対する要求を実行します。 正規表現が redirect-rule/(.*) の要求のパスに一致し、パスが /redirected/1234/5678 に置き換えられます。 リダイレクト URL が、"302 - 検出" 状態コードでクライアントに返されます。 ブラウザーは、ブラウザーのアドレス バーに表示されるリダイレクト URL に新しい要求を実行します リダイレクト URL にはサンプル アプリに一致するルールがないため、次のようになります。

  • 2 番目の要求は、アプリから 200 - OK 応答を受け取ります。
  • 応答の本文では、リダイレクト URL が示されています。

URL が "リダイレクト" されるときに、サーバーへのラウンドトリップが実行されます。

警告

リダイレクト ルールを設定するときは注意してください。 リダイレクト ルールは、リダイレクト後を含めて、アプリへのすべての要求で評価されます。 "無限リダイレクトのループ" が誤って作成されることがよくあります。

元の要求: /redirect-rule/1234/5678

リダイレクトを追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

かっこ内に含まれる式の一部は、キャプチャ グループと呼ばれます。 式のドット (.) は、どの文字とも一致することを意味します。 アスタリスク (*) は、直前の文字に 0 回以上一致することを示します。 そのため、URL の最後の 2 つのパス セグメント 1234/5678 は、キャプチャ グループ (.*) によってキャプチャされます。 要求 URL で redirect-rule/ の後に指定した任意の値が、この単一のキャプチャ グループによってキャプチャされます。

置換文字列では、キャプチャされたグループがドル記号 ($) を使用して文字列に挿入され、その後にキャプチャのシーケンス番号が続きます。 最初のキャプチャ グループ値は、$1 で取得され、2 番目は $2 で取得され、これらは正規表現内のキャプチャ グループの順序で続行されます。 サンプル アプリでは、リダイレクト ルールの正規表現内に 1 つのキャプチャ グループだけがあるので、置換文字列に 1 つの挿入されたグループ ($1) だけがあります。 ルールが適用されるときに、URL /redirected/1234/5678 になります。

セキュリティで保護されたエンドポイントへの URL リダイレクト

HTTP 要求を、同じホストとパスに HTTPS プロトコルを使用してリダイレクトするには、AddRedirectToHttps を使用します。 状態コードが指定されていない場合、ミドルウェアは既定で "302 - 検出" に設定します。 ポートが指定されていない場合は、次のようになります。

  • ミドルウェアの既定値 null に設定されます。
  • スキームは https (HTTPS プロトコル) に変更されて、クライアントはポート 443 でリソースにアクセスします。

次の例では、状態コードを "301 - Moved Permanently" に設定し、ポートを 5001 に変更する方法を示します。

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

セキュリティで保護されていない要求を、セキュリティで保護された HTTPS プロトコル (ポート 443) を使用して同じホストとパスにリダイレクトするには、AddRedirectToHttpsPermanent を使用します。 ミドルウェアによって状態コードが 301 - Moved Permanently に設定されます。

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

Note

リダイレクト規則を追加せずにセキュリティで保護されたエンドポイントにリダイレクトするときは、HTTPS リダイレクト ミドルウェアを使用することをお勧めします。 詳細については、「HTTPS の適用」のトピックをご覧ください。

サンプル アプリは、AddRedirectToHttps または AddRedirectToHttpsPermanent の使用方法の例を示すことができます。 拡張メソッドを RewriteOptions に追加します。 任意の URL でセキュリティ保護されていない要求をアプリに対して行います。 自己署名証明書が信頼できないことを示すブラウザーのセキュリティ警告を消去するか、証明書を信頼する例外を作成します。

AddRedirectToHttps(301, 5001): http://localhost:5000/secure を使用する元の要求

HTTPS へのリダイレクトを追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

AddRedirectToHttpsPermanent: http://localhost:5000/secure を使用する元の要求

HTTPS へのリダイレクト (永続) を追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

URL 書き換え

URL 書き換えのルールを作成するには、AddRewrite を使用します。 最初のパラメーターには、着信 URL のパスに一致する正規表現が含まれています。 2 番目のパラメーターは、置換文字列です。 3 番目のパラメーター skipRemainingRules: {true|false} は、現在のルールが適用される場合に追加の書き換えルールをスキップするかどうかをミドルウェアに示します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

元の要求: /rewrite-rule/1234/5678

書き換えを追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

式の先頭にあるキャレット (^) は、URL パスの先頭からマッチングが開始されることを意味します。

前のリダイレクト ルール redirect-rule/(.*) の例では、正規表現の先頭にキャレット (^) がありません。 したがって、パスの redirect-rule/ の前にどのような文字があっても一致します。

パス 一致したもの
/redirect-rule/1234/5678 はい
/my-cool-redirect-rule/1234/5678 イエス
/anotherredirect-rule/1234/5678 はい

書き換えルール ^rewrite-rule/(\d+)/(\d+) は、rewrite-rule/ で始まる場合のみパスと一致します。 次の表では、一致の違いに注意してください。

パス 一致したもの
/rewrite-rule/1234/5678 はい
/my-cool-rewrite-rule/1234/5678 いいえ
/anotherrewrite-rule/1234/5678 いいえ

式の ^rewrite-rule/ に続く部分に、2 つのキャプチャ グループ (\d+)/(\d+) があります。 \d は、1 桁 (数字) に一致することを示します。 プラス記号 (+) は、直前の 1 つ以上の文字に一致することを意味します。 そのため、URL は、数字とその後に続くスラッシュ、さらにその後に続く別の数字を含んでいる必要があります。 これらのキャプチャ グループが $1 および $2 として書き換えられた URL に挿入されます。 書き換えルールの置換文字列は、クエリ文字列にキャプチャされたグループを配置します。 /rewrite-rule/1234/5678 の要求されたパスは、/rewritten?var1=1234&var2=5678 でリソースを取得するように書き換えられます。 クエリ文字列が元の要求に存在する場合、URL が書き換えられるときに保持されます。

リソースを取得するためのサーバーへのラウンドトリップはありません。 リソースが存在する場合は、取得され、200 - OK 状態コードと共にクライアントに返されます。 クライアントはリダイレクトされていないため、ブラウザーのアドレス バーの URL は変更されません。 クライアントは、URL の書き換え操作がサーバーで発生したことを検出できません。

Note

式内の照合ルールは計算量が多く、アプリの応答時間が長くなるので、可能な限り skipRemainingRules: true を使用します。 最も高速なアプリの応答を実現するには以下のようにします。

  • 一致する頻度が最も多いルールから一致頻度が最も少ないルールへの順番で書き換えルールを並べ替えます。
  • 一致が発生し、追加の処理が必要ないときに残りのルールの処理をスキップします。

Apache mod_rewrite

AddApacheModRewrite を使用して Apache mod_rewrite ルールを適用します。 ルール ファイルがアプリと共に展開されていることを確認します。 mod_rewrite ルールの情報と例については、「Apache mod_rewrite」を参照してください。

ApacheModRewrite.txt ルール ファイルからルールを読み取るには、StreamReader を使用します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、要求を /apache-mod-rules-redirect/(.\*) から /redirected?id=$1 にリダイレクトします。 応答の状態コードは "302 -検出" です。

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

元の要求: /apache-mod-rules-redirect/1234

Apache mod リダイレクトを追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

ミドルウェアは、次の Apache mod_rewrite サーバー変数をサポートします。

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

IIS URL リライト モジュールのルール

IIS URL リライト モジュールに適用される同じルール セットを使用するには、AddIISUrlRewrite を使用します。 ルール ファイルがアプリと共に展開されていることを確認します。 Windows Server IIS で実行されているときにミドルウェアでアプリの web.config ファイルを使用するように指定しないでください。 IIS を使用する場合、IIS リライト モジュールとの競合を避けるため、これらのルールをアプリの web.config の外部に保存する必要があります。 IIS URL リライト モジュールのルールの詳細と例については、「Using Url Rewrite Module 2.0」(URL リライト モジュール 2.0 の使用 ) と「URL Rewrite Module Configuration Reference」(URL リライト モジュール構成リファレンス) を参照してください。

IISUrlRewrite.xml ルール ファイルからルールを読み取るには、StreamReader を使用します。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、要求を /iis-rules-rewrite/(.*) から /rewritten?id=$1 に書き換えます。 応答は、200 - OK 状態コードでクライアントに送信されます。

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

元の要求: /iis-rules-rewrite/1234

IIS URL 書き換えを追加する: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

望ましくない方法でアプリに影響するように構成されたサーバー レベル ルールを使用するアクティブな IIS リライト モジュールがある場合は、アプリに対して IIS リライト モジュールを無効にできます。 詳細については、「Disabling IIS modules」 (IIS モジュールの無効化) を参照してください。

サポートされていない機能

ASP.NET Core 2.x でリリースされたミドルウェアは、次の IIS URL リライト モジュールの機能をサポートしていません。

  • 送信ルール
  • カスタム サーバー変数
  • ワイルドカード
  • LogRewrittenUrl

サポートされるサーバー変数

ミドルウェアは、次の IIS URL リライト モジュール サーバー変数をサポートします。

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

Note

PhysicalFileProvider を介して IFileProvider を取得することもできます。 このアプローチは、書き換えルール ファイルの場所に関する大きな柔軟性を提供する場合があります。 書き換えルール ファイルを指定したパスでサーバーに導入されていることを確認してください。

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

メソッド ベースのルール

メソッド内で独自のルール ロジックを実装するには、Add を使用します。 AddRewriteContext を公開し、メソッドで HttpContext を使用できるようにします。 RewriteContext.Result は、追加のパイプライン処理の実行方法を決定します。 次の表で説明する RuleResult フィールドのいずれかに値を設定します。

コンテキストの書き換えの結果 アクション
RuleResult.ContinueRules (既定値) ルールの適用を続けます。
RuleResult.EndResponse ルールの適用を停止し、応答を送信します。
RuleResult.SkipRemainingRules ルールの適用を停止し、次のミドルウェアにコンテキストを送信します。
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリは、 .xml で終了するパスの要求をリダイレクトするメソッドの例を示します。 /file.xml に対して要求が行われた場合、要求は /xmlfiles/file.xml にリダイレクトされます。 状態コードは 301 - Moved Permanently に設定されます。 ブラウザーが /xmlfiles/file.xml に対する新しい要求を行うと、静的ファイル ミドルウェアはクライアントに wwwroot/xmlfiles フォルダーからファイルを提供します。 リダイレクトの場合は、応答の状態コードを明示的に設定します。 それ以外の場合は、200 - OK 状態コードが返され、クライアントでのリダイレクトは発生しません。

RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

このアプローチでは、要求を書き換えることもできます。 サンプル アプリでは、wwwroot フォルダーから file.txt テキスト ファイルを提供するためにテキスト ファイル要求のパスを書き換える処理が示されています。 静的ファイル ミドルウェアでは、更新された要求パスに基づいてファイルが提供されます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs:

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

IRule ベースのルール

IRule インターフェイスを実装するクラス内のルール ロジックを使用するには、Add を使用します。 IRule では、メソッド ベースのルール アプローチを使用する場合より高い柔軟性が提供されます。 実装クラスには、ApplyRule メソッドに対してパラメーターを渡すことができるコンストラクターを含めることができます。

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

サンプル アプリの extensionnewPath のパラメーターの値は、いくつかの条件を満たすかチェックされます。 extension は、値を含んでいる必要があり、値は .png.jpg、または .gif でなければなりません。 newPath が有効ではない場合、ArgumentException がスローされます。 image.png に対して要求が行われた場合、要求は /png-images/image.png にリダイレクトされます。 image.jpg に対して要求が行われた場合、要求は /jpg-images/image.jpg にリダイレクトされます。 状態コードは 301 - Moved Permanently に設定され、context.Result はルールの処理を停止して応答を送信するように設定されます。

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

元の要求: /image.png

image.png 用: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

元の要求: /image.jpg

image.jpg 用: 要求および応答を追跡する開発者ツールを備えたブラウザー ウィンドウ

正規表現の例

Goal 正規表現文字列と
一致の例
置換文字列と
出力の例
クエリ文字列内のパスを書き換える ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
末尾のスラッシュを除去する (.*)/$
/path/
$1
/path
末尾のスラッシュを強制する (.*[^/])$
/path
$1/
/path/
特定の要求を書き換えを回避する ^(.*)(?<!\.axd)$ または ^(?!.*\.axd$)(.*)$
はい: /resource.htm
いいえ: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
URL セグメントを再配置する path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
URL セグメントを置き換える ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

その他の技術情報