スポンサードリンク

【mod_rewrite】「.htaccess」での設定時の注意点

サーバーApacheのモジュールmod_rewriteでURL書き換えを行うとき、「httpd.conf」ではなく「.htaccess」で設定する場合が多いと思います。

しかしこの場合、注意点があります。

スポンサードリンク

最初に戻ってマッチングされる

mod_rewriteでURL書き換えを行う際、RewriteRuleを一つだけ記述する場合は特に気にしなくてよいのですが、複数個記述する場合は注意が必要です。

それは、マッチングが終了した際、再度最初からマッチングされるからです。

例えば、以下を記述した「.htaccess」をルートディレクトリに設置したとします。

RewriteEngine On
RewriteRule ^index.html index2.html  ・・・①
RewriteRule ^index3.html index4.html ・・・②
RewriteRule ^index2.html index3.html ・・・③

この場合、「http://○○○.com/index.html」でアクセスした場合、「index3.html」が出力されそうです。

しかし、実際は「index4.html」が出力されます。

書き換えの挙動

URL書き換えの挙動を追っていくと、このようになります。

「http://○○○.com/index.html」でアクセスがあった場合、RewriteRuleに「index.html」が渡される。
   ↓
①ではパターンマッチして「index2.html」に書き換えられる
   ↓
②ではパターンマッチしない
   ↓
③でパターンマッチして「index3.html」に書き換えられる
   ↓
ここで書き換え終了かと思いきや、最初に戻る
   ↓
①ではパターンマッチしない
   ↓
②ではパターンマッチして「index4.html」に書き換えられる
   ↓
これ以降はパターンマッチしないのでここで終了

このように、いったんマッチが終了したあと、再度最初からマッチングされていきます。

何度も最初に戻ってマッチングされる

では、次の場合はどうでしょうか。

RewriteEngine On
RewriteRule ^index.html index2.html  ・・・①
RewriteRule ^index4.html index5.html ・・・②
RewriteRule ^index3.html index4.html ・・・③
RewriteRule ^index2.html index3.html ・・・④

この場合、先ほどの例に沿って「index4.html」かな?と思いますが、「index5.html」が出力されます。

書き換えの挙動

書き換えの挙動を追うと、このようになります。

「http://○○○.com/index.html」でアクセスがあった場合、RewriteRuleに「index.html」が渡される。
   ↓
①ではパターンマッチして「index2.html」に書き換えられる
   ↓
②ではパターンマッチしない
   ↓
③ではパターンマッチしない
   ↓
④でパターンマッチして「index3.html」に書き換えられる
   ↓
これ以降はマッチングされないが、終了せずに最初に戻る
   ↓
①ではパターンマッチしない
   ↓
②ではパターンマッチしない
   ↓
③ではパターンマッチして「index4.html」に書き換えられる
   ↓
これ以降はマッチングされないが、さらに最初に戻る
   ↓
①ではパターンマッチしない
   ↓
②ではパターンマッチして「index5.html」に書き換えられる
   ↓
これ以降はパターンマッチしないので、さらに最初に戻る
   ↓
これ以降はマッチングしないので「index5.html」でフィニッシュ

このように、「.htaccess」でのmod_rewriteは、何度も何度も最初に戻ってマッチングしていき、何もマッチされなくなるまで書き換え処理が行われます。

永久ループの危険性

「何度も何度も最初に戻ってマッチングする」というmod_rewriteの仕様のせいで、永久ループに陥る危険性がグンとあがります。

例えば、次のような場合は永久ループになります。

RewriteEngine On
RewriteRule ^index.html index2.html
RewriteRule ^index3.html index4.html
RewriteRule ^index2.html index3.html
RewriteRule ^index4.html index.html

この場合、「500 Internal Server Error」が返され、ページ閲覧が不能になります。

対処法

このように永久ループになる危険性がある場合は、 「何度も何度も最初に戻ってマッチングする」というmod_rewriteの仕様を見越して記述を工夫しなければなりません。

例えば、以下のようにフラグ「L」を仕込んでおくなどです。

RewriteEngine On
RewriteRule ^index.html index2.html
RewriteRule ^index3.html index4.html
RewriteRule ^index4.html - [L]
RewriteRule ^index2.html index3.html
RewriteRule ^index4.html index.html

また、これまではRewriteRuleのパターン部分はシンプルなものを記述しましたが、「^(.*)$」などの大雑把な正規表現を使うと永久ループの危険性が高まります。

こういう場合は、ディレクトリを含めて書いたり( ^abc/(.*)$ )、拡張子を指定したり( ^(.*\.html)$ )して対策を講じます。

追記

「.htaccess」でのmod_rewrite設定は、Lフラグ(パターンマッチした場合に、それ以降の書き換えはしないように指定するフラグ)を記述しても意味がないようです(詳しくは「.htaccess」でのLフラグは意味がない?を参照)。

また、httpd.confに記述しても、記述場所がDirectoryセクションであった場合は、「.htaccess」での設定と同様に最初に戻ってマッチングされます(詳しくは「httpd.conf」での設定方法を参照)。

そのため、RewriteCondを用いるのが最も簡単な対処法だと思います。

なお、外部にリダイレクト、つまりRフラグとLフラグを指定しておけば、その時点でリダイレクトされますので最初に戻って・・・みたいなことにはなりません。

まとめ

「.htaccess」での設定(および「httpd.conf」での設定であってもDirectoryセクションに記述した場合)は処理が終わっても最初に戻ってマッチングされる。

永久ループにならないよう工夫する必要がある(RewriteCondを使ってルール条件を定義するのが最もよい)。

参考サイト

.htaccess ファイルで mod_rewrite の設定をする時の注意点

コメント

まだコメントはありません。

コメントフォーム
お名前
コメント