結論
mod_rewriteで設定した環境変数にmod_rewriteでアクセスする場合、変数名の最初に'REDIRECT_'がつく
背景
laravelで動いているサービスでメンテナンスモードを追加したい。
laravelにメンテナンスモードの仕組みはあるけど、特定のapiだけはメンテナンスモード中でも使いたいとか、特定のIPからはメンテナンス中でも使えるようにしたいけど、URLにシークレットコードつけたりは難しいなどがあり、.htaccessをゴニョゴニョすることで対応しようとした。
条件
- /api/aaa はメンテナンス中でも使いたい
- それ以外のapiは403を返す
- api以外のアクセスはccc.htmlを表示
- favicon.icoは表示
- ほんとはもうちょっと条件あったけど、例として簡単にした
とりあえすこんな感じで書いてみた
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# aaa以外のapiは403 ・・・ ①
RewriteCond %{REQUEST_URI} /api
RewriteCond %{REQUEST_URI} !/api/aaa
RewriteRule ^.*$ - [F,L]
# API以外のアクセスはccc.htmlを表示 ・・・ ②
RewriteCond %{REQUEST_URI} !/(api|favicon.ico|ccc.html)
RewriteRule ^.*$ /ccc.html [L]
・・・
# Send Requests To Front Controller... ・・・ ③
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
結果、/api/aaa以外のapiは403になったし、api以外はccc.htmlが表示された
しかし、/api/aaaにアクセスするとccc.htmlが返ってきた
③で/api/aaa が index.phpにrewriteされた後、また上から評価されて、②でapi以外なのでccc.htmlにrewriteされてしまった
②でindex.phpを対象外にすれば良さそうだけど、index.phpにアクセスされた場合に素通りしてしまう
rewriteする前のURLを判定できればなんとかなりそうだということで・・・
一時的に変数に元のURLを保持してみた
RewriteRule時のフラグのE or ENVでapacehの環境変数に値を設定できるらしい
RewriteCondでは%{ENV:・・・}でapacheの環境変数を使用できるらしい
ということで、③でindex.phpにrewrite時に元のURLを環境変数に設定しておいて、再評価時に②で/api/aaaからrewriteされたアクセスは除外すればいけそうかなとこんな感じで試してみた。
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# aaa以外のapiは403 ・・・ ①
RewriteCond %{REQUEST_URI} /api
RewriteCond %{REQUEST_URI} !/api/aaa
RewriteRule ^.*$ - [F,L]
# API以外のアクセスはccc.htmlを表示 ・・・ ②
RewriteCond %{REQUEST_URI} !/(api|favicon.ico|ccc.html)
RewriteCond %{ENV:ORG_URI} !/api/aaa
RewriteRule ^.*$ /ccc.html [L]
・・・
# Send Requests To Front Controller... ・・・ ③
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [E:ORG_URI=%{REQUEST_URI},L]
</IfModule>
結果、/api/aaaにアクセスするとccc.htmlが帰ってきてしまう・・・
ログを出してみて確認すると、確かに③で環境変数ORG_URIに/api/aaaを入れているようだが、再評価時の②のORG_URIは空になっている??
結局・・・
調べてみると、どうやらmod_rewriteのEフラグで環境変数に設定したものは、mod_rewriteの変数ENV:で取得する場合は、頭に「REDIRECT_」がつくらしい!!
ということで、
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# aaa以外のapiは403 ・・・ ①
RewriteCond %{REQUEST_URI} /api
RewriteCond %{REQUEST_URI} !/api/aaa
RewriteRule ^.*$ - [F,L]
# API以外のアクセスはccc.htmlを表示 ・・・ ②
RewriteCond %{REQUEST_URI} !/(api|favicon.ico|ccc.html)
RewriteCond %{ENV:REDIRECT_ORG_URI} !/api/aaa
RewriteRule ^.*$ /ccc.html [L]
・・・
# Send Requests To Front Controller... ・・・ ③
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [E:ORG_URI=%{REQUEST_URI},L]
</IfModule>
これで、/api/aaaは使えるようになった
参考サイト