URL Rewriting Middleware - 日本語意訳

- 2017/07/07(Fri) 時点の情報に基づいています
- 公式ドキュメント：[URL Rewriting Middleware](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting)


# ASP.NET Core の URL Rewriting Middleware

By [Luke Latham](https://github.com/GuardRex) and [Mikael Mengistu](https://github.com/mikaelm12)

[View or download sample code](https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/url-rewriting/sample)

URL 書き換えは、1つ以上の事前定義されたルールに基づいてリクエスト URL を変更する行為です。URL 書き換えは、リソースのロケーションとそのアドレス間の抽象化を生成し、ロケーションとアドレスが緊密にリンクされないようにします。URL 書き換えが重要なシナリオはいくつかあります：

* サーバーリソース用の安定したロケーターを維持しつつ、一時的または永続的に移動または置換する

* 異なるアプリケーション間または1つのアプリケーションの複数の領域にわたるリクエスト処理を分割する

* 受信したリクエストに対して URL セグメントの削除、追加、または再編成を行う

* 検索エンジン最適化（SEO）のためにパブリック URL を最適化する

* 親しみやすいパブリック URL を使うことで、リンクをたどって見つけるコンテンツを予測しやすくする

* 安全でないリクエストを安全なエンドポイントへリダイレクト

* 画像への直リンクを防止

正規表現（regex）マッチ​​ングルール、Apache mod_rewrite モジュールに基づくルール、IIS Rewrite Module に基づくルール、独自のメソッドとクラスルールロジックなど、いくつかの方法で URL を変更するルールを定義できます。このドキュメントでは、ASP.NET Core アプリケーションで URL Rewriting Middleware の使用方法について説明とともに紹介します。

> [!注意]
> URL 書き換えは、アプリケーションのパフォーマンス低下させる可能性があります。実行可能な場合には、ルールの数や複雑さを制限すべきです。

## URL リダイレクト と URL 書き換え
*URL リダイレクト* と *URL 書き換え* の言葉上の違いはほとんどないように最初は思えるかもしれませんが、クライアントにリソースを提供する点において重要な意味合いを含んでいます。ASP.NET Core の URL Rewriting Middleware は両方のニーズを満たすことができます。

*URL リダイレクト* はクライアントサイドの操作で、クライアントは他のアドレスのリソースにアクセスするよう指示されます。そのためサーバーへの往復が必要となります。クライアントに返されたリダイレクト URL は、クライアントが新しいリクエストを発行してリソースを取得する際に、ブラウザのアドレスバーに表示されます。もし `/resource` が `/different-resource` へ *リダイレクトされている* 場合、クライアントが `/resource` へリクエストを行うと、サーバーは、クライアントが `/different-resource` にあるリソースを取得する必要があることを、リダイレクトが一時的または永続的であることを示すステータスコードと共にレスポンスします。クライアントはリダイレクト URL 先にあるリソースへのリクエストを新たに実行します。

![A WebAPI service endpoint has been temporarily changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The server sends back a 302 (Found) response with the new, temporary path for the service at version 2 /v2/api. The client makes a second request to the service at the redirect URL. The server responds with a 200 (OK) status code.](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/url_redirect.png)

リクエストを別の URL にリダイレクトする際、リダイレクトが永続的であるか一時的であるかが示されます。301 (Moved Permanently) ステータスコードは、リソースに新しい永続 URL があり、将来のすべてのリソース要求で新しい URL を使用するようにクライアントに指示する場合に使用されます。クライアントは 301 ステータスコードを受け取るとレスポンスをキャッシュします。302 (Found) ステータスコードは、クライアントが将来リダイレクト URL を保存して再利用しないように、リダイレクトが一時的または一般的に変更される場合に使用されます。詳細については [RFC 2616: Status Code Definitions](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) を参照してください。

*URL 書き換え* はサーバーサイドの操作で、異なるリソースアドレスからリソースを提供します。URL 書き換えはサーバーへの往復が必要ありません。書き換えられた URL はクライアントに返却されないので、ブラウザのアドレスバーに表示されません。`/resource` が `/different-resource` に *書き換えられる* 場合、クライアントが `/resource` へリクエストすると、サーバーは `/different-resource` にあるリソースを内部的に取得します。クライアントは書き換えられた URL 上のリソースを検索することができる可能性はありますが、リクエストを行ってレスポンスを受け取った際に書き換えられた URL 上にリソースが存在することは知らされません。

![A WebAPI service endpoint has been changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The request URL is rewritten to access the service at the version 2 path /v2/api. The service responds to the client with a 200 (OK) status code.](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/url_rewrite.png)

## URL 書き換えサンプルアプリケーション
[URL書き換えサンプルアプリケーション](https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/url-rewriting/sample) では URL Rewriting Middleware の機能を詳しく見ることができます。このアプリケーションでは、書き換えルールとリダイレクトルールが適用されており、結果として書き換えられた URL またはリダイレクトされた URL が表示されます。

## いつ URL Rewriting Middleware を使うべきか
Windows Server 上の IIS の [URL Rewrite module](https://www.iis.net/downloads/microsoft/url-rewrite)、Apache Server 上の [Apache mod_rewrite module](https://httpd.apache.org/docs/2.4/rewrite/)、[URL rewriting on Nginx](https://www.nginx.com/blog/creating-nginx-rewrite-rules/) が使用できない場合、あるいは、アプリケーションが [WebListener server](xref:fundamentals/servers/weblistener) 上でホストされている場合、URL Rewriting Middleware を使用してください。IIS、Apache、Nginx などのサーバーベースの URL書き換え技術を使用する主な理由は、この Middleware がこれらのモジュールの全機能をサポートしておらず、ミドルウェアのパフォーマンスがおそらくモジュールのパフォーマンスにマッチしないからです。ただし、IIS Rewrite Module の `IsFile` や `IsDirectory` 制約など、ASP.NET Core プロジェクトでは使用できないサーバーモジュールの機能がいくつかあります。このようなシナリオでは、代わりにこの Middleware を使用することができます。

## パッケージ
この Middleware をプロジェクトに含めるには、[`Microsoft.AspNetCore.Rewrite`](https://www.nuget.org/packages/Microsoft.AspNetCore.Rewrite/) パッケージへの参照を追加します。この Middleware は .NET Framework 4.5.1 または .NET Standard 1.3 以降のバージョンに依存しています。この機能は、ASP.NET Core 1.1.0 以降を対象とするアプリケーションで使用できます。

## 拡張とオプション
`RewriteOptions` クラスのインスタンスを生成し、各ルールの拡張メソッドを使用して、URL 書き換えおよび URL リダイレクトのルールを作成します。処理したい順序で複数のルールをチェーン化します。`RewriteOptions` は URL Rewriting Middleware に渡され、`app.UseRewriter(options);` でリクエストパイプラインに追加されます.

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

### URL リダイレクト
`AddRedirect()` を使ってリクエストをリダイレクトします。第一引数は受信した URL パスをマッチングするための正規表現を含みます。第二引数は置換文字列です。第三引数が存在する場合は、ステータスコードを指定します。ステータスコードを指定しない場合は、302（Found）がデフォルトになり、リソースが一時的に移動または置換されたことを示します。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

開発者ツールが有効になっているブラウザで、パス `/redirect-rule/1234/5678` でサンプルアプリケーションにリクエストします。正規表現は `redirect-rule/(.*)` のリクエストパスとマッチし、パスは `/redirected/1234/5678` に置き換えられます。リダイレクト URL は 302（Found）のステータスコードでクライアントに返送されます。ブラウザはリダイレクト URL で新しいリクエストを行い、その際 URL がブラウザのアドレスバーに表示されます。サンプルアプリケーション中のどのルールもリダイレクト URL と一致しないため、2番目のリクエストはアプリケーションから 200（OK）レスポンスを受信し、レスポンスの本文にはリダイレクト URL が表示されます。URL がリダイレクトされる場合、サーバーへの完全な往復が行われます。

Original Request: `/redirect-rule/1234/5678`

![Browser window with Developer Tools tracking the requests and responses](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect.png)

括弧で囲まれた正規表現の一部は *キャプチャグループ* と呼ばれます。ドット (`.`) は *任意の文字と一致* することを意味し、アスタリスク (`*`)  は *前の文字と0回以上一致* することを意味します。従って、URL の最後の2つのパスセグメント`1234/5678` は、キャプチャグループ `(.*)` によってキャプチャされます。リクエスト URL 中の `redirect-rule/` の後に指定されたどんな値も、この単一のキャプチャグループによってキャプチャされます。

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

<a name=url-redirect-to-secure-endpoint></a>
### 安全なエンドポイントへの URLリダイレクト
`AddRedirectToHttps()` を使用して、安全でないリクエストを、安全な HTTPS プロトコル (https://) で同じホストとパスにリダイレクトします。ステータスコードとポートは柔軟に選択できます。ステータスコードが指定されない場合、Middleware は 302 (Found)
 をデフォルトにします。ポートが指定されない場合、Middleware は `null` をデフォルトにします。これは、プロトコルが `https://` に変わり、クライアントが 443 ポートでリソースにアクセスすることを意味します。この例では、ステータスコードを301 (Moved Permanently) に設定し、ポートを 5001 に変更する方法を示しています。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirectToHttps(301, 5001);

app.UseRewriter(options);
```

`AddRedirectToHttpsPermanent()` を使用して、安全でないリクエストを安全な HTTPS プロトコル (ポート443 の `https://`) で同じホストとパスにリダイレクトします。Middleware はステータスコードを 301 (Moved Permanently) に設定します。 

サンプルアプリケーションでは、 `AddRedirectToHttps()` または `AddRedirectToHttpsPermanent()` の使用方法を示すことができます。 拡張メソッドを `RewriteOptions()` に追加します。任意の URL で安全でないリクエストをアプリケーションに対して行います。ブラウザでレスポンスを確認するには、おそらく自己署名証明書が信頼できないというブラウザのセキュリティ警告を無視する必要があります。

Original Request using `AddRedirectToHttps(301, 5001)`: `/secure`

![Browser window with Developer Tools tracking the requests and responses](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect_to_https.png)

Original Request using `AddRedirectToHttpsPermanent()`: `/secure`

![Browser window with Developer Tools tracking the requests and responses](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect_to_https_permanent.png)

### URL 書き換え
`AddRewrite()` を使用して、URL 書き換えルールを生成します。第一引数は受信した URL パスをマッチングするための正規表現を含みます。第二引数は置換文字列です。第三引数の  `skipRemainingRules: {true|false}` は、現在のルールが適用された場合に、追加の書き換えルールをスキップするかどうかを Middleware に示します。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

Original Request: `/rewrite-rule/1234/5678`

![Browser window with Developer Tools tracking the request and response](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_rewrite.png)

正規表現で最初に気づくのは、最初のキャレット (`^`) です。これは、URL パスの先頭からマッチングが開始されることを意味します。

先ほどのリダイレクトルール `redirect-rule/(.*)` の例では、正規表現の先頭にはキャレットがありませんでした。従って、マッチしたパスの `redirect-rule/` の前には何らかの文字が先行する可能性があります。

Path | Match
--- | :---:
`/redirect-rule/1234/5678` | Yes
`/my-cool-redirect-rule/1234/5678` | Yes
`/anotherredirect-rule/1234/5678` | Yes

書き換えルール `^rewrite-rule/(\d+)/(\d+)` はパスが `rewrite-rule/` から始まる場合にのみマッチします。以下の書き換えルールと上記のリダイレクトルールとのマッチングの違いに注目してください。

Path | Match
--- | :---:
`/rewrite-rule/1234/5678` | Yes
`/my-cool-rewrite-rule/1234/5678` | No
`/anotherrewrite-rule/1234/5678` | No

正規表現 `^rewrite-rule/` 部分に続きて、2つのキャプチャグループ `(\d+)/(\d+)` があります。 `\d` は *digit (number) と一致すること* を意味します。プラス記号 (`+`) は、*前の文字の1つ以上と一致すること* を意味します。従ってURL は、数字、スラッシュ、数字が順に続く文字列を含まなくてはなりません。これらのキャプチャグループは書き換え URL の `$1` と `$2` に挿入されます。書き換えルールの置換文字列は、キャプチャグループをクエリ文字列に配置します。`/rewrite-rule/1234/5678` というリクエストパスは書き換えられて `/rewritten?var1=1234&var2=5678` にあるリソースを取得します。もしクエリ文字列が元のリクエストに存在する場合、URL が書き換えられた際に保存されます。

リソースを取得するためのサーバーへの往復はありません。もしリソースが存在すれば、フェッチされ、200 (OK) のステータスコードでクライアントに返されます。クライアントはリダイレクトされないので、ブラウザのアドレスバーの URL は変わりません。クライアントに関する限り、URL 書き換え操作は一度も発生しません。

> [!注意]
> 可能な限り `skipRemainingRules: true` を使用すべきです。なぜなら、マッチングルールは高価なプロセスであり、アプリケーションの応答時間が遅くなるからです。アプリケーションの応答を最も高速にするには、書き換えルールの並び順を、最も頻度の高いマッチングルールを先に、最も頻度の低いマッチングルールを後にすることです。また、マッチングが発生し追加のルールの処理が必要ない場合には残りのルールの処理をスキップすることです。

### Apache mod_rewrite
`AddApacheModRewrite()` を使用して Apache mod_rewrite ルールを 適用することができます。第一引数には `IFileProvider` をとりますが、これは [Dependency Injection](dependency-injection.md) によって `IHostingEnvironment` が注入されるので、そこから提供される `ContentRootFileProvider` になります。第二引数はルールファイルのパスです。このサンプルアプリケーションでは *ApacheModRewrite.txt* となります。このルールファイルがアプリケーションとともに配布されていることを確認しなければなりません。mod_rewrite ルールの詳細と例については、[Apache mod_rewrite](https://httpd.apache.org/docs/2.4/rewrite/)を参照してください。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

このサンプルアプリケーションはリクエストを `/apache-mod-rules-redirect/(.\*)` から `/redirected?id=$1` にリダイレクトします。レスポンスのステータスコードは 302 (Found) になります。

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

Original Request: `/apache-mod-rules-redirect/1234`

![Browser window with Developer Tools tracking the requests and responses](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_apache_mod_redirect.png)

##### サポートされるサーバー変数
Middleware は以下の 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 Rewrite Module ルール
IIS URL Rewrite Module に通常適用されるルールを使用するには、`AddIISUrlRewrite()` を使用します。第一引数には `IFileProvider` をとり、一方、第二引数は XML ルールファイルへのパスとなり、このサンプルアプリケーションでは *IISUrlRewrite.xml* となります。このルールファイルがアプリケーションとともに配布されていることを確認しなければなりません。このルールを *web.config* ファイルで指定しないでください。これらのルールは *web.config* の外部に保存して、IIS　Rewrite Module ルールとの競合を避ける必要があります。IIS URL Rewrite Module ルールの詳細と例については、 [Using Url Rewrite Module 2.0](https://www.iis.net/learn/extensions/url-rewrite-module/using-url-rewrite-module-20) and [URL Rewrite Module Configuration Reference](https://www.iis.net/learn/extensions/url-rewrite-module/url-rewrite-module-configuration-reference) を参照してください。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

このサンプルアプリケーションはリクエストを `/iis-rules-rewrite/(.*)` から `/rewritten?id=$1` に書き換えます。レスポンスはステータスコード 200 (OK) でクライアントに送られます。

```xml:XML
<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>
```

Original Request: `/iis-rules-rewrite/1234`

![Browser window with Developer Tools tracking the request and response](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_iis_url_rewrite.png)

もしアクティブな IIS Rewrite Module を使用しており、望ましくない方法でアプリケーションに影響するサーバーレベルのルールが構成されている場合は、アプリケーションの IIS Rewrite Module を無効にすることができます。詳細については
 [Disabling IIS modules](xref:hosting/iis-modules#disabling-iis-modules) を参照してください。

#### サポートされない機能
Middleware は以下の IIS URL Rewrite Module 機能をサポートしません:
* Global rules ([Basic Middleware #169](https://github.com/aspnet/BasicMiddleware/pull/169))
* Rewrite Maps ([Basic Middleware #168](https://github.com/aspnet/BasicMiddleware/pull/168))
* CustomResponse action ([Basic Middleware #135](https://github.com/aspnet/BasicMiddleware/issues/135))
* Custom Server Variables ([Basic Middleware #183](https://github.com/aspnet/BasicMiddleware/issues/183))
* trackAllCaptures ([Basic Middleware #178](https://github.com/aspnet/BasicMiddleware/pull/178))
* Wildcards
* LogRewrittenUrl

#### サポートされるサーバー変数
Middleware は以下の IIS URL Rewrite Module サーバー変数をサポートします：
* 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

> [!注意]
> `PhysicalFileProvider` を介して `IFileProvider` を取得することもできます。この方法は、書き換えルールファイルの場所の柔軟性を高めることができます。書き換えルールファイルが、指定したパスのサーバーにデプロイされていることを確認してください。

>```csharp:C#
>PhysicalFileProvider fileProvider = new >PhysicalFileProvider(Directory.GetCurrentDirectory());
>```

### メソッドベースのルール
`Add(Action<RewriteContext> applyRule)` を使用して、独自のルールロジックをメソッドに実装します。`RewriteContext` は `HttpContext` を公開し、メソッドの中で使用できます。`context.Result` は追加のパイプライン処理の処理方法を決定します。

`context.Result` | Action
--- | ---
`RuleResult.ContinueRules` (default) | ルールの適用を続ける
`RuleResult.EndResponse` | ルールの適用を停止し、レスポンスを送る
拡張機能オプション
`RuleResult.SkipRemainingRules` | ルールの適用を停止し、コンテキストを次のミドルウェアに送る

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

このサンプルアプリケーションは、`.xml` で終わるパスのリクエストをリダイレクトするメソッドを示しています。`/file.xml` をリクエストすると、`/xmlfiles/file.xml` にリダイレクトされます。ステータスコードは 301 (Moved Permanently) にセットされています。リダイレクトの場合は、レスポンスのステータスコードを明示的にセットしなければなりません。さもないと、200 (OK) ステータスコードが返され、クライアント側でリダイレクトが発生しません。

```csharp:C#
static void RedirectXMLRequests(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("/xmlfiles")))
    {
        return;
    }

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

Original Request: `/file.xml`

![Browser window with Developer Tools tracking the requests and responses for file.xml](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect_xml_requests.png)

### IRule ベースのルール
`Add(IRule)` を使用して、`IRule` から派生したクラスに独自のルールロジックを実装します。`IRule` を使用すると、メソッドベースのルールアプローチを使用するよりも柔軟性が向上します。派生クラスに引数をとれるコンストラクタを用意して、その引数を `ApplyRule` メソッドで使用するようにすることも可能です。

```csharp:C#
var options = new RewriteOptions()
    .AddRedirect("redirect-rule/(.*)", "redirected/$1")
    .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", skipRemainingRules: true)
    .AddApacheModRewrite(env.ContentRootFileProvider, "ApacheModRewrite.txt")
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml")
    .Add(RedirectXMLRequests)
    .Add(new RedirectImageRequests(".png", "/png-images"))
    .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

app.UseRewriter(options);
```

サンプルアプリケーション内の `extension` と `newPath` の引数の値はいくつかの条件を満たすようチェックされます。`extension` は必須で、*.png*、*.jpg*、または *.gif* でなければなりません。`newPath` が有効でない場合は、`ArgumentException` がスローされます。*image.png* へリクエストを行った場合、`/png-images/image.png` へリダイレクトされます。*image.jpg* へリクエストを行った場合、`/jpg-images/image.jpg` へリダイレクトされます。ステータスコードが 301 (Moved Permanently) にセットされ、`context.Result` がセットされ、ルールの処理は中断されレスポンスが返されます。

```csharp:C#
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("The extension is not valid. The extension must be .png, .jpg, or .gif.", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("The path is not valid. Provide an alphanumeric path that starts with a forward slash.", 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 = StatusCodes.Status301MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = _newPath + request.Path + request.QueryString;
        }
    }
}
```

Original Request: `/image.png`

![Browser window with Developer Tools tracking the requests and responses for image.png](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect_png_requests.png)

Original Request: `/image.jpg`

![Browser window with Developer Tools tracking the requests and responses for image.jpg](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/url-rewriting/_static/add_redirect_jpg_requests.png)

## 正規表現の例

目的 | 正規表現文字列 &<br>マッチング例 | 置換文字列 &<br>出力結果例
--- | :---: | :---:
パスをクエリストリングに書き換え | `^path/(.*)/(.*)`<br>`/path/abc/123` | `path?var1=$1&var2=$2`<br>`/path?var1=abc&var2=123`
末尾のスラッシュを削除 | `(.*)/$`<br>`/path/` | `$1`<br>`/path`
末尾のスラッシュを強制 | `(.*[^/])$`<br>`/path` | `$1/`<br>`/path/`
特定のリクエストの書き換え回避 | `(.*[^(\.axd)])$`<br>Yes: `/resource.htm`<br>No: `/resource.axd` | `rewritten/$1`<br>`/rewritten/resource.htm`<br>`/resource.axd`
URLセグメントの並べ替え | `path/(.*)/(.*)/(.*)`<br>`path/1/2/3` | `path/$3/$2/$1`<br>`path/3/2/1`
URLセグメントの置換 | `^(.*)/segment2/(.*)`<br>`/segment1/segment2/segment3` | `$1/replaced/$2`<br>`/segment1/replaced/segment3`

## Resources
* [Application Startup](startup.md)
* [Middleware](middleware.md)
* [Regular expressions in .NET](https://docs.microsoft.com/en-us/dotnet/articles/standard/base-types/regular-expressions)
* [Regular expression language - quick reference](https://docs.microsoft.com/en-us/dotnet/articles/standard/base-types/quick-ref)
* [Apache mod_rewrite](https://httpd.apache.org/docs/2.4/rewrite/)
* [Using Url Rewrite Module 2.0 (for IIS)](https://www.iis.net/learn/extensions/url-rewrite-module/using-url-rewrite-module-20)
* [URL Rewrite Module Configuration Reference](https://www.iis.net/learn/extensions/url-rewrite-module/url-rewrite-module-configuration-reference)
* [IIS URL Rewrite Module Forum](https://forums.iis.net/1152.aspx)
* [Keep a simple URL structure](https://support.google.com/webmasters/answer/76329?hl=en)
* [10 URL Rewriting Tips and Tricks](http://ruslany.net/2009/04/10-url-rewriting-tips-and-tricks/)
* [To slash or not to slash](https://webmasters.googleblog.com/2010/04/to-slash-or-not-to-slash.html)