上位階層の .htaccess で書き換えられた Cache-Control ヘッダを修復する
あるディレクトリ以下 (/app とする) でアプリケーションを作成したが、アプリケーション側で出力している Cache-Control が効かない。原因を調べてみると上位階層の .htaccess で mod_headers を使って Cache-Control: no-cache と書き換えられていた。
サーバの環境は次の通り。
- HTTP(S)サーバ: Apache/2.2.15
- .htaccess が有効
- mod_headers, mod_rewrite が有効
- アプリケーションの実行: モジュール版PHP
- ユーザのアップロードした画像は、実ファイルを配置せずアプリケーションを通して出力している(ここで Cache-Control ヘッダを設定)
mod_headers の基本的な使用方法
上位階層の .htaccess では次の記述がなされていた。
Header set Cache-Control "no-cache" Header set Pragma "no-cache"
この設定がある場合、アプリケーションでキャッシュの方法や期限を設定していても、応答ヘッダが次のように書き換えられてしまう。
Cache-Control: no-cache Pragma: no-cache
Header ディレクティブの動作は次の7通り(Apache 2.2系, 2.2.9以降)で、既存の設定を解除し、Apache のキャッシュ設定を使用する方法はないようだ。
set | 応答ヘッダを設定する |
---|---|
add | 応答ヘッダを追加する。同じ名前のヘッダがある場合は、複数の同じ名前のヘッダができる |
append | 既に存在する同じ名前のヘッダに値を追加する。既存の値の後ろにカンマ区切りで追加 |
merge | append と同様だが、同じ値がある場合は追加しない |
unset | 指定した名前の応答ヘッダを削除する |
echo | リクエストヘッダと同じ名前の応答ヘッダを返す |
edit | 既存の応答ヘッダを正規表現によって置き換える |
ファイルの種類によって応答ヘッダを設定
上位階層でなされた設定を解除する方法がないので、ファイルの種類によってひとつひとつ応答ヘッダを設定することにした。
RewriteEngine On RewriteBase /app ## 静的ファイルだった場合に環境変数を設定 RewriteRule \.(css|js|png|jpg|gif|svg|svgz)$ - [E=StaticAssets:1] ## アップロードファイルに環境変数を設定 ## (Query string を設定する方法以外はうまくいかなかった) RewriteRule ^uploads/(.*) index.php?_uploads [QSA] RewriteCond %{QUERY_STRING} ^_uploads RewriteRule ^ - [E=AppUploads:1] ## アプリケーションのルーティング用設定 RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ index.php [QSA,L] ## 静的ファイルのキャッシュ設定 Header set Cache-Control "public, max-age=86400" env=StaticAssets Header set Pragma "cache" env=StaticAssets ## アップロードファイルのキャッシュ設定 Header set Cache-Control "public, max-age=31536000" env=AppUploads Header set Pragma "cache" env=AppUploads ## 設定の確認用 Header set X-Env "%{StaticAssets}e / %{AppUploads}e"