Ajax通信 の キャッシュ 機能

0 件のコメント

JavaScript で 非同期通信 をしようとしたとき、その通信結果をクライアント側でキャッシュしたりしなかったり… 実際のところどうなっているか、どうやったら良いのかを見ていきます。

XMLHttpRequest の 仕様

まずは仕様について見てみます。

いわゆる、XMLHttpRequest の仕様 ── W3C の ワーキングドラフト の キャッシュ に関する部分(send メソッド の下の方) ── では以下のようなことが述べられています。

  • スクリプトで明示的に指定がない限り Cache-ControlPragma を勝手に付加しない
  • 304 Not Modified のときは、200 OK と同じ挙動をする

では、これらを元に、キャッシュする 通信方法 と、キャッシュしない 通信方法 はどうしたら良いかを、 具体的なサンプルコードを交えながら以下で見ていきます。

キャッシュ する

何もしなければ、デフォルトでキャッシュされます。 通信した内容がブラウザにキャッシュされて、キャッシュされたデータを使った 200 OK が返ってきます。

サンプルコード(サーバー側:C# & ASP.NET MVC)

public ActionResult Test()
{
    // レスポンス用のサンプルデータを作成
    var o = new
    {
        Message = "foo-bar",
        DateTime = DateTime.Now.ToString("r")
    };

    // 作成したデータを返信
    return this.Json(o, JsonRequestBehavior.AllowGet);
}

サンプルコード(クライアント側:JavaScript)

var xhr = new XMLHttpRequest();
var url = 'http://localhost/BrowserCacheTest/Home/Test';
var responseText = '';

xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        responseText = xhr.responseText;
    }
};
xhr.send();

通信の様子

このシーケンスだけだと分かりませんが、上記サンプルコードの リクエスト を何度も実行しています。 つまり、キャッシュされた通信の場合、以下のような特徴があると言えそうです。

  • 通信は1度だけ実行され、以降は行われない
  • スクリプトは毎回 200 OK を受け取る

キャッシュ しない

無意味なクエリパラメータを末尾につけて URL を異なるものにすることで、キャッシュしない… という方法もありますが、ここでは HTML通信 の ヘッダ にキャッシュ制御を付記することで「キャッシュ しない」を実現します。

「キャッシュ する」場合との違いは、 サーバー側でレスポンスヘッダーに Cache-Control: no-cachePragma: no-cache を記述するようにしている点です。 これらをサーバー側で指定することによって、クライアント側は該当する通信をキャッシュしなくなります。

サンプルコード(サーバー側:C# & ASP.NET MVC)

public ActionResult Test()
{
    // レスポンス用のサンプルデータを作成
    var o = new
    {
        Message = "foo-bar",
        DateTime = DateTime.Now.ToString("r")
    };

    // キャッシュしないようヘッダーを追加
    this.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    this.Response.AddHeader("Pragma", "no-cache");

    // 作成したデータを返信
    return this.Json(o, JsonRequestBehavior.AllowGet);
}

サンプルコード(クライアント側:JavaScript)

var xhr = new XMLHttpRequest();
var url = 'http://localhost/BrowserCacheTest/Home/Test';
var responseText = '';

xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        responseText = xhr.responseText;
    }
};
xhr.send();

通信の様子

通信がキャッシュされず、毎回取得し直されていることが分かります。 また、レスポンスヘッダーに Cache-Control: no-cachePragma: no-cacheExpires: -1 が指定されていることも分かります。

というわけで…ブラウザにキャッシュさせたくない場合、サーバー側の レスポンス ヘッダー を指定することで実現できるようでした。