RewriteRuleディレクティブ:URLのリライト/リダイレクトを行う
RewriteRule ディレクティブは、 URL のリライトを実際にどのように行うのかを定義します。クライアントからのリクエストに対して、指定した正規表現パターンにマッチした場合に URL のリライトを実行します。またフラグを設定してリライトの方法を指定することもできます。ここでは Apache の RewriteRule ディレクティブの使い方について解説します。
(Last modified: )
目次
RewriteRuleディレクティブの使い方
RewriteRule ディレクティブはリライトをどのように行うのかルールを定義するために使用します。書式は次のとおりです。
RewriteRule 正規表現パターン 置換URL [フラグ]
記述できる場所は httpd.conf, VirtualHost, Directory, .htaccess です。 .htaccess で設定する場合は AllowOverride FileInfo が設定されている必要があります。
RewriteRule ディレクティブでは最初にクライアントからのリクエストが正規表現パターンとマッチするかどうかを調べます。マッチした場合は、置換 URL で指定した URL にリクエストを置き換えます。
リクエストのどの部分が正規表現パターンと比較されるのか
最初にクライアントからのリクエストの中で、どの部分が正規表現パターンとマッチするかどうかの対象となるのかについてです。クライアントからのリクエストが次のようなものだった場合で考えてみます。
http://www.example.com/blog/hello.html?num=10
正規表現パターンとマッチするかどうか対象となるのは、ホスト名とポート番号のあとからクエリーの前までの部分です。 RewriteRule ディレクティブが Directory ディレクティブのブロック内で記述されている場合、または .htaccess で記述されている場合に対象となるのは次の赤い文字の部分となります。
http://www.example.com/blog/hello.html?num=10
注意点として RewriteRule ディレクティブが VirtualHost ディレクティブのブロック内で記述されている場合、対象となるのは先頭の / を含めた次の赤い文字の部分となります。
http://www.example.com/blog/hello.html?num=10
どこで RewriteRule ディレクティブが記述されているのかによってパターンと比較する対象の文字列が異なるので注意してください。
また .htaccess の中で使用する場合で、 .htaccess がサブディレクトリの中に設置されている場合、そのサブディレクトリからの部分が対象となります。例えば blog ディレクトリの中に .htaccess が設置されていた場合は対象となる文字列は次の部分です。( Directory ディレクティブのブロックの中に記述する場合で、サブディレクトリが対象の場合も同じです)。
http://www.example.com/blog/hello.html?num=10
正規表現パターンを指定する
リクエストの中の対象の文字列が、指定した正規表現パターンとマッチした場合に URL のリライトが実行されます。 Apache で使用する正規表現は Perl 互換のものです。例えば blog/hello.html とマッチするパターンは次のように記述できます。
^blog/hello\.html$
^ は先頭とマッチし、 $ は末尾とマッチします。この正規表現は、先頭から blog/hello.html で始まり、そしてこの文字列の後には何も記述されていない文字列とマッチします。
正規表現パターンを次のように記述しても blog/hello.html とマッチしますが、この場合は myblog/hello.html や blog/hello.htmls などにもマッチします。
blog/hello\.html
※ 正規表現を使った詳しいパターンの記述方法については「正規表現入門」を参照されてください。
置換URLを指定する
クライアントからのリクエストが正規表現パターンとマッチした場合、リクエストが置換 URLに指定したページの内容にリライト(外部のサイトの場合はリダイレクト)されます。置換 URL の記述方法は次の 4 つの方法があります。
相対パスで指定する場合は .htaccess が設置されているディレクトリからの相対パスで指定します。例えば /old ディレクトリに .htaccess がある場合に /blog/bye.html のページの内容でリライトする場合は次のように記述します。( Directory ディレクティブのブロックの中に記述する場合で、サブディレクトリが対象の場合も同じです)。
../blog/bye.html
※ 相対パスの基準となるディレクトリを RewriteBase ディレクティブを指定することもできます。詳しくは「RewriteBaseディレクティブ:リライト/リダイレクト先を相対パスで指定するときの基準ディレクトリを指定する」を参照されてください。
ドキュメントルートからの絶対パスで指定することもできます。例えば /blog/bye.html のページの内容でリライトする場合は次のように記述します。
/blog/bye.html
他のサイトの URL を指定した場合にはリライトではなくリダイレクトされます。リダイレクト先の URL を http:// などから始まる URL を指定します。現在のサイト内のページを http:// などから始まる URL で記述した場合、同じサイトだった場合にはリダイレクトではなくリライトされますのでご注意ください。
http://www.example.jp/myblog/hey.html
なお置換 URL として - を記述した場合にはリライトは行われません。フラグだけを適用する場合などに利用します。
-
リライトとリダイレクトの違い
RewriteRule ディレクティブを使用した場合、置換 URL として同じサイトのページを指定した場合にはリライトが行われ、別のサイトのページを指定した場合にはリダイレクトが行われます。
リライトというのは、ブラウザのアドレスバーに表示される URL は元のままですが、表示されるページの内容がリライト先のページの内容になります。それに対してリダイレクトというのはリダイレクト先の URL へ改めてリクエストが送信されるため、ブラウザのアドレスバーに表示される URL もリダイレクト先のものになります。
ただ RewriteRule ディレクティブで置換 URL として同じサイトのページを指定した場合でも、フラグで [R=301] のように指定することでリライトではなくリダイレクトにすることができます。(詳しくはフラグの箇所で解説します)。
# リライト RewriteRule ^index\.html$ /new/index.html # リダイレクト RewriteRule ^index\.html$ /new/index.html [R=301] # リダイレクト RewriteRule ^index\.html$ http://www.example.com/
RewriteRuleディレクティブの動作確認
それでは実際に RewriteRule ディレクティブを記述してみます。今回は次のような設定を行うために、ドキュメントルート内の blog ディレクトリに .htaccess を設置し、その中で設定を記述します。
・ /blog/hello_old.html を /blog/hello_new.html へリライト
・ /blog/bye_old.html を /blog/bye_new.html へリダイレクト
・ /blog/search を https://www.google.co.jp/ へリダイレクト
最初に対象のディレクトリで .htaccess を使って設定を変更できるように httpd.conf ファイルに設定を追加します。 httpd.conf ファイルの末尾に次のように記述しました。対象のディレクトリに対して AllowOverride FileInfo を設定します。( AllowOverride ディレクティブについては「AllowOverrideディレクティブ:.htaccessを使った設定の上書きを許可する」を参照されてください)。
<Directory "${SRVROOT}/htdocs/blog"> AllowOverride FileInfo </Directory>
また mod_rewrite モジュールが組み込まれているかどうかも確認してください。( mod_rewrite モジュールを組み込む手順については「mod_rewriteモジュールを組み込む」を参照されてください)。
httpd.conf ファイルを保存したら Apache を再起動しておいてください。
次に .htaccess ファイルを作成します。テキストエディタで次のように記述してください。(今回はサブディレクトリの /blog に .htaccesss を設置するので、パターンと一致するかどうか調べるのは /blog のあとの部分です)。
RewriteEngine on RewriteRule ^hello_old\.html$ /blog/hello_new.html RewriteRule ^bye_old\.html$ /blog/bye_new.html [R=301,L] RewriteRule ^search$ https://www.google.co.jp/
作成したファイルをドキュメントルートの下の blog ディレクトリに .htaccess という名前で保存しました。
他に blog ディレクトリには hello_new.html と bye_new.html を作成して設置してあります。
それでは最初に http://localhost/blog/hello_old.html へアクセスしてください。
置換 URL が同じサイト内のページなので、リライトが行われます。その為、アクセスした URL はそのままで、置換 URL で指定した /blog/hello_new.html のページの内容が画面に表示されます。
次に http://localhost/blog/bye_old.html へアクセスしてください。
置換 URL が同じサイト内のページですが、フラグで [R=301] が指定されているのでリダイレクトが行われます。その為、置換 URL で指定した /blog/bye_new.html のページが画面に表示されます。(アドレスバーに表示される URL はリダイレクト先の URL になります)。
最後に http://localhost/blog/search へアクセスしてください。
置換 URL が別のサイトのページのためリダイレクトが行われます。その為、置換 URL で指定した https://www.google.co.jp/ のページが画面に表示されます。
このように RewriteRule ディレクティブを使用することで、リライトだけでなくリダイレクトも行うことができます。
複数のRewriteRuleディレクティブが記述されている場合に連続してリライトが行われるかどうか
複数の RewriteRule ディレクティブが記述されている場合、リクエストに対して一度だけではなく複数回リライトやリダイレクトが行われる場合があります。 例として /blog ディレクトリに .htaccess を設置し、次のような設定を記述した場合で試してみます。
RewriteEngine on RewriteRule ^index_A\.html$ /blog/index_B.html [R=301] RewriteRule ^index_B\.html$ /blog/index_C.html [R=301]
ブラウザから http://localhost/blog/index_A.html へアクセスすると、 .htaccess に記述された順番に正規表現パターンとマッチするかどうか調べていきます。今回の場合はまず最初の RewriteRule ディレクティブにマッチするため /blog/index_B.html へリダイレクトされたあと、二番目の RewriteRule ディレクティブにマッチするため /blog/index_C.html へリダイレクトされます。
次に .htaccess を次のように変更します。先ほどとは RewriteRule ディレクティブが記述された順序が変わっています。
RewriteEngine on RewriteRule ^index_B\.html$ /blog/index_C.html [R=301] RewriteRule ^index_A\.html$ /blog/index_B.html [R=301]
ブラウザから http://localhost/blog/index_A.html へアクセスすると、今回の場合はまず二番目の RewriteRule ディレクティブにマッチするため /blog/index_B.html へリダイレクトされたあと、それ以降には RewriteRule ディレクティブが存在しないためこれで終わりになるように思われますが、実際には今回も /blog/index_C.html へリダイレクトされます。
これは .htaccess に記述された RewriteRule ディレクティブのいずれかにマッチした場合、次の行からマッチしないか調べるのではなく改めて .htaccess の先頭からマッチするかどうか調べていくためです。その為、まず /blog/index_B.html へリダイレクトされたあと、あらためて最初の RewriteRule ディレクティブにマッチして /blog/index_C.html へリダイレクトされます。
なお正規表現にマッチしてリライトやリダイレクトが行われたあと、これ以上他の RewriteRule ディレクティブとマッチするかどうか調べないようにするためのフラグとして [L] フラグや [END] フラグが用意されています。フラグについてはこのあと解説します。
フラグを設定する
RewriteRule ディレクティブではフラグを設定することでリライトを行う挙動を変更することができます。
RewriteRule 正規表現パターン 置換URL [フラグ]
複数のフラグを設定する場合はカンマ(,)で区切って記述します。空白などをいれないようにご注意ください。
[フラグA,フラグB]
数多くのフラグが用意されていますが、ここではよく使用するフラグに限定して開設します。
Lフラグ
これ以上のリライトを行いません。
RewriteRule 正規表現パターン 置換URL [L]
次の .htaccess を見てください。 index_A.html にアクセスすると、まず index_B.html へリダイレクトされます。 [L] フラグがない場合はこのあとあらためて index_B.html から index_C.html へリダイレクトが行われますが、 [L] フラグがある場合は最初のリダイレクトを行った時点でこれ以上のリダイレクトは行いません。
RewriteEngine on RewriteRule ^index_B\.html$ /blog/index_C.html [R=301,L] RewriteRule ^index_A\.html$ /blog/index_B.html [R=301,L]
ただし [L] フラグをつけても最初のリダイレクトを行ったあとで、あらためて先頭から RewriteRule ディレクティブの正規表現パターンとマッチするものがないか調べる場合もあるので注意が必要です。
Nフラグ
最後にリライトが行われた URL を対象として .htaccess (やその他の設定)の先頭から RewriteRule ディレクティブの正規表現パターンとマッチするものがないか調べます。
RewriteRule 正規表現パターン 置換URL [N]
R[=code]フラグ
リライトではなくリダイレクトを行います。 code には HTTP ステータスコードを指定できます。例えば永続的なリダイレクトを表す 301 リダイレクトを行いたい場合は R=301 、一時的なリダイレクトを表す 302 リダイレクトを行いたい場合は R=302 を指定します。 code を省略した場合は 302 でリダイレクトが行われます。
RewriteRule 正規表現パターン 置換URL [R=301]
NEフラグ
& や # などの特殊な文字を 16 進数のコードにエスケープしないようにします。例えば置換 URL にハッシュ(#)が含まれている場合、 NE フラグを設定していないと # が %23 にエスケープされてしまいリライトが正常に行われません。
RewriteRule 正規表現パターン 置換URL [NE]
例えば /blog ディレクトリに .htaccess を設置し次のように記述します。
RewriteEngine on RewriteRule ^index_A\.html$ /blog/index_C.html#section1 [R=301] RewriteRule ^index_B\.html$ /blog/index_C.html#section2 [R=301,NE]
ブラウザから /blog/index_A.html へアクセスすると /blog/index_C.html#section1 へリダイレクトされるのですが、 NE フラグが記述されていないためハッシュ(#)が %23 にエスケープされてしまいリダイレクト先が見つからなくなります。
ブラウザから /blog/index_B.html へアクセスすると /blog/index_C.html#section2 へリダイレクトされるのですが、 NE フラグが記述されているためハッシュ(#)がエスケープされず目的の URL へリダイレクトされます。
NCフラグ
[NC] フラグは正規表現パターンがマッチするかどうかを評価するときに大文字と小文字を区別しません。
RewriteRule 正規表現パターン 置換URL [NC]
Fフラグ、Gフラグ
[F] フラグと [G] フラグはリライトを実行する代わりにエラーを返す場合に使用します。置換 URL として - を記述します。
RewriteRule 正規表現パターン - [F] RewriteRule 正規表現パターン - [G]
[F] フラグを記述した場合はクライアントには 403 Forbidden が返されます。 [G] フラグを記述した場合はクライアントには 410 Gone が返されます。
例えば /blog ディレクトリに .htaccess を設置し次のように記述します。
RewriteEngine on RewriteRule ^index_A\.html$ - [F] RewriteRule ^index_B\.html$ - [G]
ブラウザから /blog/index_A.html へアクセスすると 403 Forbidden が返されます
ブラウザから /blog/index_B.html へアクセスすると 410 Gone が返されます。
QSA
[QSA] フラグとリクエストに付けられていたクエリー文字列と置換 URL に指定したクエリー文字列をまとめてリライトまたはリダイレクト先に付加する場合に使用します。
RewriteRule 正規表現パターン - [QSA]
詳しい使い方はこのあとのクエリー文字列の扱いの箇所をご覧ください。
E=[!環境変数名][:値]
[E=環境変数名] フラグは正規表現パターンがマッチした場合に環境変数名に対して値を設定します。
RewriteRule 正規表現パターン 置換URL [E=環境変数名]
例えば次のような使い方をすることができます。
RewriteEngine on RewriteCond AAA ^BBB(CCC)$ RewriteRule ^(.*)$ - [E=TEST:%1] RewriteCond %{ENV:TEST} DDD RewriteRule EEE FFF [L]
最初の RewriteCond ディレクティブでリクエストの一部の値を取得し、次の RewriteRule ディレクティブで後方参照を使って環境変数 TEST に取得した値を設定します。続いて次の RewriteCond ディレクティブで環境変数 TEST の値が DDD とマッチした場合、その次の記述された RewriteRule ディレクティブを評価します。
END
[END] フラグは Apache 2.4.0 以降から利用できるフラグで、内部リダイレクトをここで終了させます。 [L] フラグと使い方は似ています。
RewriteRule 正規表現パターン 置換URL [END]
次の .htaccess を見てください。 index_A.html にアクセスすると、まず index_B.html へリダイレクトされます。 [END] フラグがない場合はこのあとあらためて index_B.html から index_C.html へリダイレクトが行われますが、 [END] フラグがある場合は最初のリダイレクトを行った時点でこれ以上のリダイレクトは行いません。
RewriteEngine on RewriteRule ^index_B\.html$ /blog/index_C.html [R=301,END] RewriteRule ^index_A\.html$ /blog/index_B.html [R=301,END]
例えば .htaccess を次のように記述します。
RewriteEngine on RewriteRule ^index_A\.html$ /blog/index_B.html [R=301,END] RewriteRule ^index_B\.html$ /blog/index_C.html [R=301,END]
ブラウザから http://localhost/blog/index_A.html へアクセスすると、今回の場合はまず二番目の RewriteRule ディレクティブにマッチするため /blog/index_B.html へリダイレクトされます。そして [END] フラグがついているため、内部リダイレクトはここで終わりとなります。
正規表現パターンで後方参照を使用する
正規表現パターンの中で括弧()で囲んだパターンとマッチした文字列を置換 URL の中で参照して使用することができます。次の例をみてください。
RewriteEngine on RewriteRule ^old/(.*)$ /new/$1 [R=301]
ドキュメントルートに設置した .htaccess に記述しました。正規表現パターンの中の .* の部分にマッチした文字列を、置換 URL の中で $1 として参照しています。
例えば /old/hello.html へアクセスがあった場合、 .* の部分には hello.html がマッチするため、 /new/hello.html へリダイレクトされます。また /old/bye.html へアクセスがあった場合、 .* の部分には bye.html がマッチするため /new/bye.html へリダイレクトされます。
後方参照を使用することで、ディレクトリに含まれるすべてのファイルを別のディレクトリに同じ名前でリダイレクトさせたい場合などに一つの RewriteRule ディレクティブで記述することができます。
クエリー文字列の扱いについて
リクエストにクエリー文字列が含まれる場合、リライトやリダイレクトされたときに同じクエリー文字列が付加されます。実際に試してみます。 .htaccess ファイルを作成し次のように記述したあと /blog/ ディレクトリに保存してください。
RewriteEngine on RewriteRule ^index_A\.html$ /blog/index_B.html [R=301]
クエリー文字列付きの http://localhost/blog/index_A.html?num=8 へアクセスします。
リクエストに付いていたクエリー文字列はリダイレクト先の URL にもクエリー文字列がそのまま付加されるので http://localhost/blog/index_B.html?num=8 へリダイレクトされます。
クエリー文字列をリライトやリダイレクト先に付加しない
リクエストに付いていたクエリー文字列をリライトやリダイレクト先に付加しないようにするには、置換 URL の最後にはてな(?)を記述します。では先ほどの .htaccess を次のように変更してください。
RewriteEngine on
RewriteRule ^index_A\.html$ /blog/index_B.html? [R=301]
クエリー文字列付きの http://localhost/blog/index_A.html?num=8 へアクセスします。
今度はリダイレクト先にはクエリー文字列が付加されずに http://localhost/blog/index_B.html へリダイレクトされます。
リライトやリダイレクト先に新しいクエリー文字列を付加する
リライトやリダイレクト先に新しいクエリー文字列を付加することは可能です。その場合、リクエストに付加されていたクエリー文字列は付加されません。では先ほどの .htaccess を次のように変更してください。
RewriteEngine on
RewriteRule ^index_A\.html$ /blog/index_B.html?flag=off [R=301]
クエリー文字列付きの http://localhost/blog/index_A.html?num=8 へアクセスします。
リダイレクト先には置換 URL で指定したクエリー文字列だけが付加されて、リクエストのクエリー文字列は付加されずに http://localhost/blog/index_B.html?flag=off へリダイレクトされます。
リクエストに付いていたクエリー文字列を消さずに、新しいクエリー文字列を追加してリライトまたはリダイレクトすることもできます。フラグの [QSA] を指定します。
RewriteEngine on RewriteRule ^index_A\.html$ /blog/index_B.html?flag=off [R=301,QSA]
クエリー文字列付きの http://localhost/blog/index_A.html?num=8 へアクセスします。
リダイレクト先にはリクエストのクエリー文字列に加えて置換 URL で指定したクエリー文字列が追加されて http://localhost/blog/index_B.html?flag=off&num=8 へリダイレクトされます。
-- --
Apache の RewriteRule ディレクティブの使い方について解説しました。
( Written by Tatsuo Ikura )
著者 / TATSUO IKURA
これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。