jQuery.ajax()リクエストヘッダーのステータスが「304 Not Modified」かどうかを確認する方法は?
jqXHR.status
200
要求されたヘッダーが「304 Not Modified」の場合でも、通常は を返します。
ifModified:true
XHRデータリクエストが壊れるため、あまり役に立ちません。
jQuery.ajax()リクエストヘッダーのステータスが「304 Not Modified」かどうかを確認する方法は?
jqXHR.status
200
要求されたヘッダーが「304 Not Modified」の場合でも、通常は を返します。
ifModified:true
XHRデータリクエストが壊れるため、あまり役に立ちません。
キャッシュヘッダーを手動で処理しないと、それは不可能です。通常、304 レスポンスはXHR API経由では利用できません:
ユーザー エージェントが生成した条件付き要求の結果である 304 Not Modified 応答の場合、ユーザー エージェントは、サーバーが適切な内容で 200 OK 応答を返したかのように動作する必要があります。
jQuery は通常、304 応答があったことを知りません。これは、ブラウザーがネットワーク上で実際に何が起こっているかについて丁寧な嘘を JavaScript に伝えるためです。
しかし、(ちょっとした) 朗報があります。Ajax で 304 レスポンスを生成することはできますが、 HTTP キャッシュ ヘッダー If-Modified-Since
を手動で設定するかIf-None-Match
、リクエストでのみ行う必要があります。
ユーザー エージェントは、リクエスト ヘッダー (例: 、 ) を設定することにより、自動キャッシュ検証を上書きできるようにする必要があります
setRequestHeader()
。この場合、304 Not Modified 応答を渡す必要があります。If-None-Match
If-Modified-Since
したがって、次のようなコードを使用できます。
var xhr = new XMLHttpRequest();
xhr.open("GET", "foo.html");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();
基本的な問題の 1 つは、送信する最終更新日またはETagをどのように知るかということです。ブラウザには、リクエストの送信に使用するキャッシュ情報がありますが、その情報は JavaScript と共有されません。Last-Modified
幸いなことに、jQuery は Ajax 応答からのおよびヘッダーを追跡するため、次にそのリソースへの要求を送信するときに、jQuery にこれらのヘッダー値を設定させるETag
ことができます。ifModified:true
これについては、次の 2 つの点に注意してください。
304 応答はデータを伝送しません。これは仕様によるものです。キャッシュを使用することを選択した場合は、データのコピーが既にキャッシュにあるはずです。サーバーからデータを取得できないことが問題である場合 (つまり、そのデータをまだ取得していないため)、なぜキャッシュを使用しているのですか? 古いデータが手元にあり、新しいデータのみが必要な場合は、キャッシュを使用する必要があります。したがって、304 でデータが返されなくても問題ありません。
jQuery にはIf-None-Match
、前回の要求から保存された最終更新日または ETag ( で使用するため) が必要です。プロセスは次のようになります。
If-Modified-Since
最初のフェッチ: jQuery にはキャッシュ情報がないため、orは送信されませんIf-None-Match
。応答が戻ってくると、サーバーは最後に変更されたデータまたは ETag を通知する場合があり、jQuery はこれらを将来の使用のために保存します。
後続のフェッチ: jQuery には最後のフェッチからのキャッシュ情報があり、そのデータをサーバーに転送します。リソースが変更されていない場合、Ajax リクエストは 304 レスポンスを受け取ります。リソースが変更された場合、Ajax リクエストは 200 レスポンスを受け取り、jQuery が次のフェッチに使用する新しいキャッシュ情報を受け取ります。
ただし、 jQueryは、ページのリロード間でキャッシュ情報 (Cookie など) を保持しません。したがって、jQuery には送信するキャッシュ情報がないため (つまり、「最初のフェッチ」のケースにリセットし直す)、ページのリロード後のリソースの最初のフェッチが 304 になることはありません。jQuery がキャッシュ情報を保持できない理由はありませんが、現時点ではそうではありません。
つまり、キャッシュ ヘッダーを使用して JavaScript 304 応答を取得できますが、特定のリソースのブラウザー独自のETag または最終更新日にはアクセスできません。そのため、ブラウザー自体はリソースに関するキャッシュ情報を認識している可能性がありますが、JavaScript コードは認識していません。その場合、ブラウザーはキャッシュ ヘッダーを使用して実際の 304 応答を取得する可能性がありますが、JavaScript コードに 200 応答を転送します。これは、JavaScript がキャッシュ情報を送信しなかったためです。
JavaScript 304 要求を実際のネットワーク 304 応答と完全に一致させることはできません。これは、ブラウザーが認識しているキャッシュ情報と JavaScript コードが認識しているキャッシュ情報が予測できない方法で異なる可能性があるためです。ただし、ほとんどの場合、304 リクエストを正しく取得できれば、ほとんどの実用的な開発ニーズには十分対応できます。
Node.js で記述されたサーバーの簡単な例を次に示します (ただし、他の言語に移植できるほど単純なはずです)。
require("http").createServer(function (req, res) {
console.log(req.headers["if-modified-since"]);
// always send Last-Modifed header
var lastModDate = "Fri, 13 Feb 2013 13:43:19 GMT";
res.setHeader("Last-Modified", lastModDate);
// if the request has a If-Modified-Since header,
// and it's newer than the last modification,
// then send a 304 response; otherwise send 200
if(req.headers["if-modified-since"] &&
Date.parse(lastModDate) <= Date.parse(req.headers["if-modified-since"])) {
console.log("304 -- browser has it cached");
res.writeHead(304, {'Content-Type': 'text/plain'});
res.end();
} else {
console.log("200 -- browser needs it fresh");
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('some content');
}
}).listen(8080);
このサーバーを実行すると、ブラウザーにページをロードし、ブラウザー コンソールで 2 つの異なるテストを実行できます。
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
このスクリプトは、ブラウザーが要求ヘッダーを提供して取得した場合でも、常に200
応答を確認します (ブラウザーがサーバーの応答ヘッダーを確認した後、最初の後のすべての要求で発生します)。If-Modified-Since
304
Last-Modifed
対照的に、このスクリプトでは常に304 応答が返されます。
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
スクリプトは独自のIf-Modified-Since
リクエスト ヘッダーを提供します (サーバーの最終更新日から 2 日後)。ブラウザが提供するものには依存しないためIf-Modified-Since
、(XHR 仕様に従って) 304 応答を表示することが許可されます。
最後に、このスクリプトは常に200
:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/");
xhr.setRequestHeader("If-Modified-Since", "Fri, 12 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }
これは、スクリプトがIf-Modified-Since
サーバーの最終更新日より前の を使用するため、サーバーは常に200
. サーバー304
は、クライアントが最新バージョンのキャッシュされたコピーを持っていないと想定しているため、送信しません (つまり、クライアントは 2 月 12 日以降に変更があったことを通知しますが、2 月 13 日に変更があったようです)。見ていない)。
また、応答がキャッシュからのものである場合、ヘッダーはキャッシュされます。私はこれをチャンスと捉えました。私のサーバーは一意の md5 ヘッダーを送信します。これは ?query=time() と同じ効果はありません。JS 側で、最新の md5 ヘッダーを現在のもので確認します。応答がキャッシュから来る前と同じ MD5 ヘッダーを受信した場合。JQuery のことはすっかり忘れていましたが、ヘッダーの設定と読み取りが可能であることがわかりました。
<?php
$oldMD5=filter_input(INPUT_SERVER,'HTTP_CONTENT_MD5',int);
if(!empty($oldMD5)){
header('Content-MD5: '.(1+(int)$oldMD5));
}
--------------------------------------------------------------
<script>
var oldMD5=0;
//your Ajax implementation
Ajax.setRequestHeader('Content-MD5',''+oldMD5);
var newMD5=parseInt(Ajax.getResponseHeader('Content-MD5'),10);
if(newMD5 && oldMD5<newMD5,10){
oldMD5=newMD5;
//not cached
}else{
//cached
}
md5 は、「デコードされたデータが最初に送信されたデータと同じであること」を確認するためのハッシュである必要があるため、これは少し悪用されます。
https://github.com/laukstein/ajax-seo/blob/cbed03222d89f6f7e75dc49ce8882c30201bbb86/index.php#L266-274に一種の実装があり ます
var cache;
$.ajax({
...
beforeSend: function() {
cache = setTimeout(function() {
console.log('The content not cached jet.');
}, 300);
},
success: function(data) {
if (cache) {
clearTimeout(cache);
}
}
});
多分これを試してみませんか?
$.ajax({
url: 'your-url',
dataType: 'script',
complete: function(xhr) {
if (xhr.status == 304) return;
// or better: if (xhr.status != 200) return;
// your code goes here
}
});