mod_rewriteでクエリ(URIの?マーク以降の部分)を参照するにはRewriteCondで%{QUERY_STRING}を調べればよい。
rNote時代のクエリ付きのリクエストをリダイレクトさせようと思い、たとえば
http://reva.s28.xrea.com/?d=2008-11-16
へのアクセスを
http://reva.s28.xrea.com/archives/date/2008/11/16/
へ書き換えるべく、.htaccessに次のような記述を加えました。
RewriteEngine on
RewriteCond %{QUERY_STRING} d=([0-9]+)-([0-9]+)-([0-9]+)
RewriteRule . /archives/date/%1/%2/%3/ [R=301,L]
しかし実際にURIが正しく変換されるか試してみると、リクエストがループしていると怒られました。
どうやら書き換え後のURIにもクエリが付加されているようで、
いつまでたってもRewriteCondを満たしてしまっていたようです。
つまり、
http://reva.s28.xrea.com/?d=2008-11-16
http://reva.s28.xrea.com/archives/date/2008/11/16/?d=2008-11-16
http://reva.s28.xrea.com/archives/date/2008/11/16/?d=2008-11-16
http://reva.s28.xrea.com/archives/date/2008/11/16/?d=2008-11-16
.
.
.
という風なリダイレクトが繰り返されていたと考えられます。
その後試行錯誤したところ、どうも書き換えURIに?が入っているとクエリの引継ぎは行われないことが分かり、
RewriteEngine on
RewriteCond %{QUERY_STRING} d=([0-9]+)-([0-9]+)-([0-9]+)
RewriteRule . /archives/date/%1/%2/%3/? [R=301,L]
と試しに書いてみたところ、期待通りに動いてしまいました。マジか。
しかも変換後のURIに?がくっついてhttp://reva.s28.xrea.com/archives/date/2008/11/16/?
のようになることもありませんでした。これは如何に。
もう少し調べてみると、だいたい次のような感じで挙動していることが分かりました。
- 書き換えURIに?が入っていなければ、元のURIのクエリを引き継ぐ
- 書き換えURIに?が入っていれば、元のURIのクエリを破棄する
- 書き換えURIに?が入っていて
[QSA]オプションがついていれば、書き換えURIに元のクエリを合成する
これらから察するに、元のURIだけでなく書き換えURIも内部で一度クエリだけを切り離されて処理された後、付け直しているのかも。
末尾に?だけ付けても実際に返されるURIにゴミが付かなかったのは、元のURIのクエリが書き換えURIの空のクエリで上書きされた後、変換後のURIを出力する際にクエリは空だから?以降は付ける必要なしと判断されているものと考えられるんじゃないでしょうか。
それにしてもクエリ破棄のために末尾に?を付けるって発想はなかった。
mod_rewrite、というか.htaccessはまだまだ分からんことが多いなあ。