Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

Cache-Controlヘッダがno-cacheな画像ファイルにFirefoxで直接アクセスした場合に2回リクエストを送信させない

何だか訳の分からないニッチな案件ですが。。。
Cache-Controlヘッダがno-cacheな画像ファイルにFirefoxで直接アクセスした場合、LiveHTTPHeadersで確認すると2回リクエストが送信されてるんですよね。。。1回目は通常のリクエスト、2回目はFirefoxのタブに縮小版を表示させるための画像を取得するため(?)のリクエストっぽいんですが、2回リクエストが送信されているのでApacheアクセスログにも当然2行残ります。
ちなみに、Chromeだと1回しかリクエストが送信されません。

で、こういう状況でFirefoxに2回リクエストさせない、かつ、毎回HTTP 200を返すようにするにはどうしたらいいか、ちょっと試してみました。

環境

  • サーバー
    • CentOS 6.4
    • Apache2.2.29(src)
  • クライアント
    • Windows 7 Professional(64ビット版)+SP1
    • Firefox35.0.1

httpd.confの初期設定

こんな感じに画像ファイルのみ"Cache-Control: no-cache"が返るように設定。

<FilesMatch \.(?i:gif|jpe?g|png)$>
    Header set Cache-Control no-cache
</FilesMatch>

とりあえず調査してみる

Cache-Controlの設定を変更してみたところ、

  • Cache-Controlヘッダをno-cacheにするとブラウザ側でキャッシュするが、タブに縮小表示する際に画像を再利用してくれればいいんだけど、"no-cache"の仕様上画像の再検証行う必要があるため、結果的に2回リクエストしてしまう
    • access_logにはHTTP 200、HTTP 304の2つのログが出力される
  • 一方、Cache-Controlヘッダをno-storeにすると、ホントにブラウザ側で画像ファイルをキャッシュしない、つまり、タブに縮小表示する画像がないので、再度リクエストして画像を取得する必要がある。これも結果的に2回リクエストを行う
    • access_logにはHTTP 200なログが2回出力される

な感じだと判明。
となると、

ブラウザにはキャッシュさせつつ、1回目のリクエスト時に画像ファイルが更新されたように見せかける

ってのが良いんじゃないかと。そうすれば、タブ表示の際は再検証不要の画像がキャッシュに残っているので余計な事はしなくなるハズ。。。

早速、試してみた

まず、ブラウザに画像をキャッシュさせるために

Header set Cache-Control no-cache

コメントアウト
続いて、「画像ファイルが更新されたように見せかける」部分は、ETagレスポンスヘッダを送信しないようにすれば良いんじゃないかと思い、以下を追加。

FileEtag None

ブラウザのキャッシュをクリアしてアクセスしたところ、Firefoxからのリクエストが1回に!うまくキャッシュを使ってくれている模様。ただし、ステータスコード

  • 1回目:HTTP 200
  • 2回目以降:HTTP 304

に。。。惜しい!
思いつく他の方法としては、

  • Last-Modifiedレスポンスヘッダ
  • If-Modified-Sinceリクエストヘッダ

の組み合わせかと。
前者の場合はリクエスト毎に未来の日時を送信する。。。うーん、面倒そう(^^;
なので、If-Modified-Sinceリクエストヘッダを無理矢理無視することに。

RequestHeader unset If-Modified-Since

ブラウザのキャッシュをクリアしてアクセスしたところ、Firefoxからのリクエストが1回、かつ、再読み込みしてもステータスコードがHTTP 200になりました。

いや、ちょっと待て

そもそも、If-Modified-Sinceリクエストヘッダを過去日時の固定値にしたらいいんじゃねーの?
>|conf||
RequestHeader set If-Modified-Since "Mon, 1 Jan 2001 00:00:00 GMT"
|

再度キャッシュをクリアしてアクセスしてみたところ、先ほどと同様、リクエスト1回、かつ、再読み込みしてもステータスコードがHTTP 200になりました。

最終的なhttpd.confの設定

Cache-Controlレスポンスヘッダではなく、If-Modified-Sinceリクエストヘッダを書き換えるようになりました。

<FilesMatch \.(?i:gif|jpe?g|png)$>
    RequestHeader set If-Modified-Since "Mon, 1 Jan 2001 00:00:00 GMT"
</FilesMatch>

ところで

Firefoxの2回リクエストするのって、何なんだろか。仕様なのかねぇ。。。:-(