2011/01/25

mod_rewrite and MultiViews

http://www.fya.jp/blog/2007/09/14/mod_rewritemultiviews/
http://httpd.apache.org/docs/2.2/content-negotiation.html

Apache には mod_rewrite というリクエストを内部で自在に書き換えるための黒魔術が備わっており、それをWebアプリケーションフレームワークでREST風なURLを解釈させるために以下のように使うのは、割とPHPな世界では普通に行われていることである。

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

これはファイルが存在してサイズが0以上のリクエストに対してはそのままリクエストを実行。そうでなければ index.php を頭につけるようにURLを書き換えている。

こうしたやり方に対して、Options MultiViews は相性が悪い場合がある。特に 同じプレフィックスのファイルが複数存在した場合がタチが悪い。

MultiViews 機能は、拡張子が表記されていないリクエストがあった場合に、それが仮に存在しない場合は拡張子ありの同じファイルを自動的に探してくれる機能である。たとえば http://example.com/hoge がリクエストされた場合に、MultiViews がドキュメントルートで有効だと hoge.txt や hoge.html 等から適当に選んでレスポンスを返してくれる。

----

ちょっと複雑だが、ここで俺がハマった mod_rewrite と MultiViews の相性でハマった例を記す。

A) ドキュメントルートで MultiViews が有効
B) 上記のような RewriteRule を設定している
C) index.php と index.html がドキュメントルートに存在する
D) この状態で、/index/search をリクエストした場合

この状態で /index/search のレスポンスが 404 だったのでびっくらこいた。本当は、index.php/search となって、フレームワーク側で PATH_INFO を解釈してほしいのに。

起こっていたことは以下のとおりである。

1. MultiViews によって、/index/search を index.html/search とApacheがみなす
2. index.html/search に RewriteRule が適用される
3. index.html が存在するので、Pass Through され、そのまま index.html/search へのリクエストとみなされる
4. index.html/search は存在しないので 404 になる

何のことだかわからないかもしれないが、要するに、Options MultiViews は意味もわからず有効にしない。そして、mod_rewrite と混ぜる場合は注意、ということである。

0 件のコメント: