日向夏特殊応援部隊

俺様向けメモ

ブラウザキャッシュの挙動を見てみる

改めて勉強したかったので、こんなテストしてみました。

Apacheの設定とテスト内容

<VirtualHost *:80>
    ServerAdmin zigorou@localhost
    DocumentRoot /home/zigorou/www/cache
    ServerName cachetest.art-code.org

    ExpiresDefault "access plus 5 minutes"

    Alias /test1 /home/zigorou/www/cache/test
    Alias /test2 /home/zigorou/www/cache/test
    Alias /test3 /home/zigorou/www/cache/test

    <Location /test1>
        FileETag None
        ExpiresActive Off
    </Location>

    <Location /test2>
        FileETag Size
        ExpiresActive Off
    </Location>

    <Location /test3>
        FileETag Size
        ExpiresActive On
    </Location>
</VirtualHost>

どういう設定かまとめると、

test no FileETag ExpiresActive
1 None Off
2 Size Off
3 Size On

ってなってて、それぞれのパスに対してIf-Modified-Since, If-None-Match, Cache-Controlヘッダを飛ばしながら200 or 304なのかどうか調べてみる。

テストスクリプト

最近のエントリはこれに繋がってた次第ですがw

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use DateTime;
use DateTime::Format::HTTP;
use HTTP::Request;
use LWP::UserAgent;
use Set::CrossProduct;
use Text::SimpleTable;

my $date = DateTime::Format::HTTP->format_datetime(DateTime->now - DateTime::Duration->new(minutes => 30));
my $entries = {
    'Cache-Control' => [q|no-cache|, q|max-age=0|, undef],
    'If-None-Match' => [q|"2232"|, q|"2222"|, undef],
    'If-Modified-Since' => [$date, undef]
};

sub request {
    my ($url, $headers) = @_;

    my $ua = LWP::UserAgent->new;
    my $req = HTTP::Request->new('GET', $url);

    for (keys %$headers) {
        $req->header($_, $headers->{$_}) if ($headers->{$_});
    }

    my $res = $ua->request($req);

    return ($req, $res);
}

my $cp = Set::CrossProduct->new([values %$entries]);
my @headers = ();

for my $header_vals ($cp->combinations) {
    my %header;

    @header{keys %$entries} = @$header_vals;
    push(@headers, \%header);
}

for my $idx (1..3) {
    my $table = Text::SimpleTable->new([6, "no"], [20, "Cache-Control"], [20, "If-None-Match"], [20, "If-Modified-Since"], [7, "status"]);
    my $url = sprintf("http://cachetest.art-code.org/test%d/logo.gif", $idx);
    my $hidx = 0;
    for my $header (@headers) {
        my ($req, $res) = request($url, $header);

        $table->row(++$hidx, values %$header, $res->code);
    }

    print "test$idx results: \n";
    print $table->draw;
}

ちなみに正しいETagは2232です。

あと、実験でアクセスしてるファイルのstatは、

$ stat test/logo.gif 
  File: `test/logo.gif'
  Size: 8754            Blocks: 12         IO Block: 1024
・evice: 3cb4a463h/1018471523d  Inode: 844424930313348  Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1006/zigorou)   Gid: (  513/    zigorou)
Access: 2007-08-13 20:14:28.437500000 +0900
Modify: 2007-08-13 20:14:28.437500000 +0900
Change: 2007-08-13 20:14:28.437500000 +0900

で昨日がLast-Modifiedになってます。

実験結果

FileETag: None, ExpiresActive Offの場合

まずは結果。

test1 results: 
.--------+----------------------+----------------------+----------------------+---------.
| no     | Cache-Control        | If-None-Match        | If-Modified-Since    | status  |
+--------+----------------------+----------------------+----------------------+---------+
| 1      | no-cache             | "2232"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 2      | no-cache             | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 3      | no-cache             |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 4      | no-cache             | "2232"               |                      | 200     |
| 5      | no-cache             | "2222"               |                      | 200     |
| 6      | no-cache             |                      |                      | 200     |
| 7      | max-age=0            | "2232"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 8      | max-age=0            | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 9      | max-age=0            |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 10     | max-age=0            | "2232"               |                      | 200     |
| 11     | max-age=0            | "2222"               |                      | 200     |
| 12     | max-age=0            |                      |                      | 200     |
| 13     |                      | "2232"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 14     |                      | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 15     |                      |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 16     |                      | "2232"               |                      | 200     |
| 17     |                      | "2222"               |                      | 200     |
| 18     |                      |                      |                      | 200     |
'--------+----------------------+----------------------+----------------------+---------'

ここから分かるのはIf-None-Matchヘッダを送ると、有無を言わさずキャッシュが無効になり、新しいコンテンツをWebサーバーが返すって事。

Cache-Controlのno-cache, max-age=0とかは全然無関係。

なのでこの状態で有効なヘッダはIf-Modified-Since, If-None-Matchで、If-None-Matchはキャッシュ無効に無条件になり、無かったときにLast-ModifiedとIf-Modified-Sinceの比較が行われて、Last-Modified以降の日時をIf-Modified-Sinceで送っておけば304が返って来る。

FileETag: Size, ExpiresActive Offの場合

結果はこちら。

test2 results: 
.--------+----------------------+----------------------+----------------------+---------.
| no     | Cache-Control        | If-None-Match        | If-Modified-Since    | status  |
+--------+----------------------+----------------------+----------------------+---------+
| 1      | no-cache             | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 2      | no-cache             | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 3      | no-cache             |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 4      | no-cache             | "2232"               |                      | 304     |
| 5      | no-cache             | "2222"               |                      | 200     |
| 6      | no-cache             |                      |                      | 200     |
| 7      | max-age=0            | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 8      | max-age=0            | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 9      | max-age=0            |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 10     | max-age=0            | "2232"               |                      | 304     |
| 11     | max-age=0            | "2222"               |                      | 200     |
| 12     | max-age=0            |                      |                      | 200     |
| 13     |                      | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 14     |                      | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 15     |                      |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 16     |                      | "2232"               |                      | 304     |
| 17     |                      | "2222"               |                      | 200     |
| 18     |                      |                      |                      | 200     |
'--------+----------------------+----------------------+----------------------+---------'

正しいETagを送ってれば、304が返って来る。逆にETagが誤っていると無条件に新しいコンテンツを取らなくてはならない。

あとはtest1と同等。
やはりCache-Controlは無関係っぽぃ。

FileETag: Size, ExpiresActive Onの場合

結果はtest2と同じ。

test3 results: 
.--------+----------------------+----------------------+----------------------+---------.
| no     | Cache-Control        | If-None-Match        | If-Modified-Since    | status  |
+--------+----------------------+----------------------+----------------------+---------+
| 1      | no-cache             | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 2      | no-cache             | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 3      | no-cache             |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 4      | no-cache             | "2232"               |                      | 304     |
| 5      | no-cache             | "2222"               |                      | 200     |
| 6      | no-cache             |                      |                      | 200     |
| 7      | max-age=0            | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 8      | max-age=0            | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 9      | max-age=0            |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 10     | max-age=0            | "2232"               |                      | 304     |
| 11     | max-age=0            | "2222"               |                      | 200     |
| 12     | max-age=0            |                      |                      | 200     |
| 13     |                      | "2232"               | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 14     |                      | "2222"               | Tue, 14 Aug 2007 07- | 200     |
|        |                      |                      | :59:19 GMT           |         |
| 15     |                      |                      | Tue, 14 Aug 2007 07- | 304     |
|        |                      |                      | :59:19 GMT           |         |
| 16     |                      | "2232"               |                      | 304     |
| 17     |                      | "2222"               |                      | 200     |
| 18     |                      |                      |                      | 200     |
'--------+----------------------+----------------------+----------------------+---------'

何が違うかと言えば、

Cache-Control: max-age=300
Expires: Tue, 14 Aug 2007 08:43:02 GMT

のようにCache-Control, Expiresヘッダをレスポンスヘッダで返すって事。
これをブラウザが受け取り通常、期限が切れて居ない場合はリクエスト自体飛ばさない事になる。


あと、奥さんのエントリも同様に見ると勉強になります。

Kazuho@Cybozu Labs: キャッシュの上手な使い方