自宅で稼働中の Apache 2.4 Web サーバをメンテした際、静的な HTML ファイルについて、304 Not Modified
レスポンスが返っていないことに気が付きました。ETag
や If-Modified-Since
ヘッダ付きでリクエストが飛んでいて、レスポンス ヘッダの ETag
と Last-Modified
は同じ値を返してきているにも関わらず、200 OK
と伴にコンテンツ全体が返ってきています。
HTML などの静的なファイルにアクセス(F5 で通常リロード、Ctrl+F5 の強制リロードではありません)すると、ファイルを更新していないにも関わらず、常に 200 OK
ステータスと伴にコンテンツ データが返ってきます。この時、リクエスト ヘッダ中の ETag
と If-Modified-Since
に対して、レスポンス ヘッダ中の ETag
と Last-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 の仕様から外れるとか何とか…