読者です 読者をやめる 読者になる 読者になる

上位階層の .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"