Ajaxのサーバとクライアントを実装する際の基礎事項(通信キャッシュ)を検討する なお,このページの内容はIE(Internet Explorer 6)で検証したものです.他のブラウザでは動作が異なる可能性があるので注意してください.
キャッシュによるAjax通信の負荷軽減Ajax通信は,通常の画面遷移に伴うリクエストより高い頻度で発生する傾向があるので, キャッシュを考えた方が良い. 考えておかないと,自分のサーバの負荷を増やしてしまうことになるし, 通信が遅いとせっかくのAjaxの操作感を損ねる可能性がある.基本的にはApacheのmod_cacheに任せるが,ページがCTRL+F5によってno-cacheリロードされたタイミングで,そのページで行っているAjax通信のキャッシュも更新したい. 以下に書いてあるように
ことによって,ページの一部がAjaxで描画されているという画面では,そのページでCTRL+F5すれば,Ajaxで描画している部分もApacheのキャッシュをスルーして最新化されるようになった.
(1) サーバ側でのキャッシュApacheのキャッシュ(mod_cache)を使う.この場合mod_cacheの仕様上, 以下の条件を満たす必要がある.
それぞれのヘッダに設定する値は,カモランドでは以下のようにしている.
こうすれば,
という動きになる. (mod_cacheでWiki(CGI)の高速化参照) Ajax通信のサーバ側プログラムでは,この内容のヘッダをHTTPレスポンスに設定する.
(2) クライアント側でのキャッシュクライアント側では,Ajax通信で受け取った結果をhiddenに格納するようにしている. そしてbodyのonLoadイベントで,もしhiddenに値が入っているならそれを使って画面を描画している.こうしておけば,別のページに遷移してからブラウザバックで戻ってきたときに,前回の表示内容を復元することができる. この内容については,Ajax実装の基礎(ブラウザバック対応)に詳細を記述している.
(3) キャッシュを更新する方法Ajaxで画面に表示する内容の元データが更新された等の理由で, Ajax通信のGETに対してサーバが返すべきレスポンスの内容が変わった時は, キャッシュを更新して最新の内容をブラウザに送信できるようにしなければならない.この場合,XMLHttpRequestによるリクエストに以下のヘッダ設定を行えば,キャッシュを更新して最新化できる.
ここには,サーバ側のキャッシュとクライアント側の両方の話が混じっているので, 以下ではそれぞれ別々に説明する.
サーバ側のキャッシュの更新サーバ側ではApacheのmod_cacheがキャッシュする.詳細はmod_cacheでWiki(CGI)の高速化に書いているが,有効期限切れではなく強制的に更新したい場合には, Cache-Controlヘッダをつけたリクエストをブラウザ(今回はXMLHttpRequest)から送ればよい. そうすると,
という動作が,サーバ上で発生する. 3.のLast-Modifiedヘッダ比較については,既に書いたようにサーバ側プログラムのHTTP応答では
を設定するので,受け取ったレスポンスの方が常に新しいことが保証される. そのため,ブラウザへのレスポンスは,必ず更新される結果になる.
クライアント側のキャッシュの更新クライアント側ではhiddenにデータを保持することを書いたが,それとは別に,IEは勝手にローカルにキャッシュしてくれる. このこと自体は別に問題ないのだが,一旦キャッシュするとその内容ばかり使うようになり, サーバを見に行ってくれない.それで,IEにローカルキャッシュの内容を使うのではなくサーバを見に行かせるために, If-Modified-Sinceヘッダの設定が必要となる. 強制更新したいので,常に成り立つようにエポック時(最も古い日時)を設定する. If-Modified-Since: Thu, 01 Jun 1970 00:00:00 GMT
(4) キャッシュを更新するタイミングでは,このキャッシュ更新をいつやれば良いのかだが,これはなかなか難問. 色々な状況に当てはまる答えは見つかりそうにない.そのため,Ajax応答の元となるコンテンツが更新されたなどの状況を人間が判断して, 人間が更新の指示を出すことにする. 更新の指示を出す方法だが, Ajax通信は,それを呼び出しているページと密接な関係にあると考えられるので,
というキャッシュ更新仕様にして,
という方法を採ることにした.
ページのキャッシュ更新と連動する方法ということで,キャッシュ更新の仕様は,
となった. ここで問題なのが,ページのキャッシュが更新されたかどうかをどうやって判断するかだ. ページのキャッシュが更新されると,サーバ側プログラムまでリクエストが行くので, カモランドの場合は
というヘッダが付加される.(PyukiWikiにキャッシュ機能をつけるの「mod_cacheと併用する場合について」 に書いてあるとおり,カモランドのWikiはそういう実装にしている) 逆に,キャッシュがそのまま返された場合は,Last-Modifiedは昔の日時となる. そこでこの性質を利用して,documentのlastModifiedが現在日時かどうかをチェックして, もし現在日時ならページのキャッシュが更新されたとみなすことにした. カモランドではXMLHttpRequestによる通信に, JKL.ParseXML を使っているので,これを少し改造することで実現している. jkl-parsexml.js の566行目付近に挿入 if (Math.abs(new Date().getTime() - Date.parse(window.document.lastModified)) < 30 * 1000) { // no-cache this.req.setRequestHeader( "Cache-Control","no-cache"); this.req.setRequestHeader( "If-Modified-Since", "Thu, 01 Jun 1970 00:00:00 GMT"); } Last-Modifiedと現在日時(new Date)の差が30秒以内なら,キャッシュが更新されたと判断している. 30秒以内とかいうのは,
なので,それなりに誤差が出そうだからです.閲覧者のマシンの時計が狂っていると,ここの制御もおかしくなります.
参考
|