Apache 2.4 Web サーバで 304 Not Modified が返ってこない

Posted by
ぴろり
Posted at
2017/02/14 10:15
Trackbacks
関連記事 (0)
Post Comment
コメントできます
Category
開発メモ カテゴリ
カバーイメージ
  • Tags
  • Photo by Shaun Wood
    • CreativeCommons
    • Attribution
    • NonCommercial
    • ShareAlike

 自宅で稼働中の Apache 2.4 Web サーバをメンテした際、静的な HTML ファイルについて、304 Not Modified レスポンスが返っていないことに気が付きました。ETagIf-Modified-Since ヘッダ付きでリクエストが飛んでいて、レスポンス ヘッダの ETagLast-Modified は同じ値を返してきているにも関わらず、200 OK と伴にコンテンツ全体が返ってきています。

この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

現象

 HTML などの静的なファイルにアクセス(F5 で通常リロード、Ctrl+F5 の強制リロードではありません)すると、ファイルを更新していないにも関わらず、常に 200 OK ステータスと伴にコンテンツ データが返ってきます。この時、リクエスト ヘッダ中の ETagIf-Modified-Since に対して、レスポンス ヘッダ中の ETagLast-Modified は同じ値になっているにも関わらずです。

環境

$ uname -a
Linux mizuho 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux
$ dpkg -l| grep apache2
2.4.10-10+deb8u7
:
$ sudo apachectl -v
Server version: Apache/2.4.10 (Debian)
Server built:   Sep 15 2016 20:44:43
$ sudo apachectrl -M
Loaded Modules:
 deflate_module (shared)
 headers_module (shared)
:

調査

 Deflate モジュール を外したところ、304 Not Modified ステータスを返すようになりました。これを糸口にネット検索してみたところ、どうやら Apache のバグのような記述があります。ただ、その日付を見ると 2008年とあって、そんな昔からのバグが今ごろ? という気もしますが…

対策

 どうも、mod_deflate でコンテンツを圧縮してレスポンスした際、ETag の末尾に付く -gzip という suffix が悪さをしているらしい。Apache 2.5 の mod_deflate から、この suffix を調整する DeflateAlterETag というディレクティブが追加されたようで、これ一発で解決しそうですが、Apache 2.4 ではまだ使えないんですね*1
 上記の英語ページをウロウロしていて、mod_header を利用した workaround が書いてあったので導入したところ、うまく動作するようになりました。

:
<Directory /var/www/>
:
    RequestHeader edit If-None-Match "^\"(.+?)(?:-gzip)*\"$" "\"$1\""
    Header edit ETag "^\"(.+?)(?:-gzip)*\"$" "\"$1-gzip\""
:
</Directory>
:

 まず、mod_header の RequestHeader ディレクティブを利用して、リクエスト ヘッダ中の If-None-Match の末尾に付いた -gzip suffix を取り除きます。この suffix は、mod_deflate が勝手に(?)くっ付けたものなのですが、この値をそのまま Apache に渡してしまうと、Apache が再計算した ETag XXX と、この XXX-gzip を比較してしまうため、ファイルが変更されたと勘違いしてしまうと想像されます。

 次に、Header ディレクティブを利用して、レスポンス ヘッダ中の ETag の末尾に、常に -gzip suffix を付けるようにしています。これは、200 OK ステータスの際には、mod_deflate によって ETag-gzip suffix が追加されるのですが、一方、304 Not Modified の際には、mod_deflate を通らず、Apache が直にレスポンスを行うので、ETag-gzip suffix がくっ付かなくなるためです。
 この workaround では、gzip 圧縮されていないコンテンツであっても -gzip suffix が無条件くっ付いてしまうので、ちょっと気持ち悪い気がしないこともないです。そこで、もう一つの方法としては、suffix を常に付けないようにするという手もあります*2。Apache 2.5 から追加される DeflateAlterETag ディレクティブNoChange を指定したことと同じ動作になりますが、HTTP/1.1 の仕様から外れるとか何とか…

この記事を Delicious に追加する   このエントリーをはてなブックマークに追加  

  1. *1 試しに書いてみたら syntax error になりました
  2. *2 上記コードのコメントアウトされた Header 行

この記事のアーカイブ

全ての記事 »
2017年
全てのカテゴリ »
電算室 » 開発メモ
全てのタグ »
, , ,

関連記事/トラックバック

関連記事/トラックバックはまだありません

この記事にトラックバックを送るには?

コメントを投稿する

 
 (必須, 匿名可, 公開, トリップが使えます)
 (必須, 匿名可, 非公開, Gravatar に対応しています)
 (必須)
スパム コメント防止のため「投稿確認」欄に ランダムな数字 CAPTCHAについて を入力してから送信してください。お手数ですがご協力のほど宜しくお願いいたします。