実例から入ります。
http://xxxxxxxx/をリクエストします。
このURLへのアクセスは始めてです。
以前、書いた Firefoxのプラグイン Live HTTP Headers でHTTP通信のみをトレースしました。
----------------------------------------------------------
以下がリクエスト内容(初回アクセス)
----------------------------------------------------------
-
GET / HTTP/1.1
-
Host: xxxxxxxx
-
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; ja; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
-
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
-
Accept-Language: ja,en-us;q=0.7,en;q=0.3
-
Accept-Encoding: gzip,deflate
-
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
-
Keep-Alive: 300
-
Connection: keep-alive
----------------------------------------------------------
以下がレスポンス内容(初回アクセス)
----------------------------------------------------------
-
HTTP/1.x 200 OK
-
Date: Mon, 07 May 2007 11:49:33 GMT
-
Server: Apache/2.2.4 (Unix)
-
Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
-
Etag: "4c602bd-2c-4c23b600"
-
Accept-Ranges: bytes
-
Content-Length: 44
-
Connection: close
-
Content-Type: text/html
そこでリロードして、再度リクエストを出しました。
----------------------------------------------------------
以下がリクエスト内容(2回目のアクセス)
----------------------------------------------------------
-
GET / HTTP/1.1
-
Host: xxxxxxxx
-
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; ja; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
-
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
-
Accept-Language: ja,en-us;q=0.7,en;q=0.3
-
Accept-Encoding: gzip,deflate
-
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
-
Keep-Alive: 300
-
Connection: keep-alive
-
If-Modified-Since: Sat, 20 Nov 2004 20:16:24 GMT
-
If-None-Match: "4c602bd-2c-4c23b600"
-
Cache-Control: max-age=0
----------------------------------------------------------
以下がレスポンス内容(2回目のアクセス)
----------------------------------------------------------
-
HTTP/1.x 304 Not Modified
-
Date: Mon, 07 May 2007 11:51:27 GMT
-
Server: Apache/2.2.4 (Unix)
-
Connection: close
-
Etag: "4c602bd-2c-4c23b600"
ここで注目は
1)初回アクセスのレスポンス中の
-
Etag: "4c602bd-2c-4c23b600"
2)2回目アクセスのリクエスト中の
-
If-None-Match: "4c602bd-2c-4c23b600"
3)2回目アクセスのレスポンス中の
-
HTTP/1.x 304 Not Modified
-
Etag: "4c602bd-2c-4c23b600"
です。
このEtagとはエンティティTAGのことで、apacheのマニュアルからから引用すると、
FileETag ディレクティブは ドキュメントがファイルに基づいたものであるときに、 ETag (エンティティタグ) 応答ヘッダフィールドを作成するときに使用する ファイルの属性を設定します。 (ETag の値はネットワークの帯域を節約するための キャッシュの管理で使われます。) Apache 1.3.22 以前では、ETag の値は 常にファイルの inode, サイズ、最終修正時刻 (mtime) から作成 されていました。FileETag ディレクティブにより、これらのどれを使うかを 選ぶことができます。
となります。
つまり、
- 静的コンテンツ(html、画像、css、javascript等)をapacheに要求するとapacheはinode, サイズ、最終修正時刻 (mtime) からEtagの値を算出してレスポンスに含めます。
- ブラウザはあるページにアクセスしようとした時に、それが自分のキャッシュにあると、If-None-Matchヘッダーに以前のEtagの値を付与してサーバーに送信します。
- apacheはリクエストを受け取って、そのEtagの値が改めて算出し直したEtagの値と等しければ「304 Not Modified」を返し、異なっていれば、レスポンスコード200と実際のコンテンツを返却します。
※ここではIf-Modified-Sinceのことは省略しています。
WWWサーバーが一台であれば、コンテンツファイルは1個しかないので、「ファイルの実際の更新」=「Etagの変更というか変化」になるので問題ないのですが、負荷分散ルーター配下にWWWサーバーが複数台あって個別にファイルを配置している場合、まったく同じ内容のファイルを置いても、どうしてもinodeが異なるゆえに異なるEtagになってしまいます。
ファイルが変更されたと認識されて、 「304 Not Modified」ではなく、レスポンスコード200と実際のコンテンツが返却されてしまいます。
例えば、負荷分散ルーターの振り分け論理がラウンドロビンだったりすると、アクセスするたびに、別のEtagになってしまい、必要以上の負荷をネットワークに与えることになります。
これを解決するために
Etagの生成をサイズ、最終修正時刻 (mtime) からのみに指定
-
FileETag MTime Size
とか
Etag自体を返却しない(この場合If-None-Matchヘッダーも送信されなくなる)
-
FileETag None
等の対応策をとります。
さらに詳しい話はまた次回に。



