JavaScript で 非同期通信 をしようとしたとき、その通信結果をクライアント側でキャッシュしたりしなかったり… 実際のところどうなっているか、どうやったら良いのかを見ていきます。
XMLHttpRequest の 仕様
まずは仕様について見てみます。
いわゆる、XMLHttpRequest
の仕様 ──
W3C の ワーキングドラフト の キャッシュ に関する部分(send メソッド の下の方)
──
では以下のようなことが述べられています。
- スクリプトで明示的に指定がない限り
Cache-Control
やPragma
を勝手に付加しない 304 Not Modified
のときは、200 OK
と同じ挙動をする
では、これらを元に、キャッシュする 通信方法 と、キャッシュしない 通信方法 はどうしたら良いかを、 具体的なサンプルコードを交えながら以下で見ていきます。
キャッシュ する
何もしなければ、デフォルトでキャッシュされます。
通信した内容がブラウザにキャッシュされて、キャッシュされたデータを使った 200 OK
が返ってきます。
サンプルコード(サーバー側:C# & ASP.NET MVC)
1 2 3 4 5 6 7 8 9 10 11 12 | public ActionResult Test() { // レスポンス用のサンプルデータを作成 var o = new { Message = "foo-bar" , DateTime = DateTime.Now.ToString( "r" ) }; // 作成したデータを返信 return this .Json(o, JsonRequestBehavior.AllowGet); } |
サンプルコード(クライアント側:JavaScript)
1 2 3 4 5 6 7 8 9 10 11 | var xhr = new XMLHttpRequest(); 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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)
1 2 3 4 5 6 7 8 9 10 11 | var xhr = new XMLHttpRequest(); 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 の フォロー」 お願いします!!