JavaScript で 非同期通信 をしようとしたとき、その通信結果をクライアント側でキャッシュしたりしなかったり… 実際のところどうなっているか、どうやったら良いのかを見ていきます。
XMLHttpRequest の 仕様
まずは仕様について見てみます。
いわゆる、XMLHttpRequest の仕様 ──
W3C の ワーキングドラフト の キャッシュ に関する部分(send メソッド の下の方)
──
では以下のようなことが述べられています。
- スクリプトで明示的に指定がない限り
Cache-ControlやPragmaを勝手に付加しない 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-cache と Pragma: 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-cache、 Pragma: no-cache、 Expires: -1 が指定されていることも分かります。
というわけで…ブラウザにキャッシュさせたくない場合、サーバー側の レスポンス ヘッダー を指定することで実現できるようでした。
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!

