Apache Rewrite 301のキャッシュ落とし穴

URL転送のためのApacheのRewrite機能については、ウェブを探せばあまたあるのだが、一つとても重要なことを思い知ったので記述しておく。それは、

ブラウザは、301転送(ブラウザによっては302、307等も)をキャッシュしてしまう

ということだ。このことを理解していなかったので、しばし悩むことになった。

症状

症状としては簡単だ。以下のような経緯である。

  • ためしに301の転送を設定してみる。
  • うまく動かないので、RewriteLog、RewriteLogLevelを設定してみる。
  • しかし、何度やっても最初の間違った設定の通りにリダイレクトされる。
  • しかも、何のログも出ない。何か壊れているのか?
  • Tomcat連携させている関係で機能しないのかと探し回るも、そのような書き込み無し。
  • 別のサイトで試してみると、うまくログが出力されている。
  • 再度、元のサイトでブラウザをリロードなどしてみても全くうまく行かない。

理由

リダイレクト時のブラウザキャッシュに説明があった。

こういうことだ、301の恒久的リダイレクトにすると、それがブラウザにキャッシュされるため、サーバ側を変更しても反映されなくなってしまう。

これを解決するには、ブラウザのキャッシュを手動で削除するしかない。リロードしてもすぐにリダイレクトされてしまうため無駄。手動キャッシュ削除しか解決方法がない。

当然のことながら、これはサーバ側では何ともならない。

解決方法

開発途中、あるいはリリース後であってもリダイレクト先を変更する可能性のある場合は、ヘッダ情報にキャッシュさせないおまじないをかける。例えば以下だ。

<DirectoryMatch "^/sample/">
    Header set Pragma no-cache
    Header set Cache-Control no-cache
</DirectoryMatch>

ちなみに

やりたかったことは単純なことだ。

「https://foobar.com/help/」以下にあるドキュメントを、「http://help.foobar.com/doc」としてアクセスさせたいのである。

もちろん、例えば「https://foobar.com/help/foo/bar/index.html」は「http://help.foobar.com/doc/foo/bar/index.html」にリダイレクトさせる。

    RewriteRule ^/help(.*)$ http://help.foobar.com/doc$1 [R=301,L]

でよい。ごく普通の正規表現が使え、各グループは$1,$2等で参照される。特に、URL内のスラッシュを特別扱いすることも無いので、上記だけで対応可能になる。