web-dev-qa-db-ja.com

jQuery.ajax()リクエストヘッダーのステータスが「304 Not Modified」かどうかを確認する方法

jQuery.ajax() リクエストヘッダーのステータスが「304 Not Modified」であるかどうかを確認する方法

jqXHR.statusは、リクエストされたヘッダーが「304 Not Modified」であっても、通常200を返します。

ifModified:true役に立たない XHRデータリクエストが破損するため、多くの場合。

47
Binyamin

キャッシュヘッダーを手動で処理しないと、それは不可能です。通常、304応答は XHR API を介して利用可能になりません:

ユーザーエージェントが生成した条件付きリクエストの結果である304 Not Modified応答の場合、ユーザーエージェントは、サーバーが適切なコンテンツを含む200 OK応答を返したかのように動作する必要があります

jQueryは通常、304応答があったことを認識しません。これは、ブラウザーがJavaScriptに対して、ネットワーク上で実際に何が起こっているかについて丁寧な嘘をついているためです。

しかし、良いニュース(種類)があります。あなたcan Ajaxに304応答を生成させますが、手動で HTTPキャッシュヘッダーIf-Modified-SinceまたはIf-None-Matchをリ​​クエストに設定するだけです。

ユーザーエージェントは、リクエストヘッダー(If-None-MatchIf-Modified-Sinceなど)を設定して、setRequestHeader()が自動キャッシュ検証をオーバーライドできるようにする必要があります。この場合、304 Not Modifiedレスポンスをパススルーする必要があります。

したがって、次のようなコードを使用できます。

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でその情報を。さいわい、jQueryはAjax応答からのLast-ModifiedおよびETagヘッダーを追跡しているため、ifModified:trueを使用して、jQueryが次にそのリソースのリクエストを送信するときにこれらのヘッダー値を設定できます。

これについて注意すべき2つの点:

  • 304応答はデータを運びません。これは仕様によるものです。キャッシングを使用することを選択した場合、仮定は次のとおりですキャッシュにすでにデータのコピーがあるはずです!サーバーからデータを取得できないことが問題である場合(つまり、そのデータがないため)、なぜキャッシュを使用しているのですか?古いデータが手元にあり、新しいデータのみが必要な場合は、キャッシュを使用する必要があります。したがって、304でデータが戻らないことは問題になりません。

  • jQueryには、前回のリクエストから保存された最終変更日またはETag(If-None-Matchで使用する)が必要です。プロセスは次のようになります。

    • 最初のフェッチ:jQueryにはキャッシュ情報がないため、If-Modified-SinceまたはIf-None-Matchを送信しません。応答が返されると、サーバーは、jQueryが将来使用するために保存する最終変更データまたはETagをアナウンスします。

    • 後続のフェッチ:jQueryは最後のフェッチからのキャッシュ情報を持ち、そのデータをサーバーに転送します。リソースが変更されていない場合、Ajaxリクエストは304応答を受け取ります。リソースが変更された場合、Ajaxリクエストは200応答を受け取り、jQueryが次のフェッチに使用する新しいキャッシュ情報も受け取ります。

    • jQuery しないただし、ページの再読み込みの間、キャッシュ情報(Cookieなど)を保持します。したがって、ページのリロード後のリソースの最初のフェッチはnever 304になります。これは、jQueryに送信するキャッシュ情報がないためです(つまり、「最初のフェッチ」の場合にリセットされます)。 jQuery できませんでしたキャッシュ情報を永続化する理由はありませんが、現時点では永続化していません。

ここで重要なのは、キャッシュヘッダーを使用してJavaScript 304応答を取得できることですが、特定のリソースのブラウザ自身の ETagまたは最終更新日にはアクセスできません。そのため、ブラウザ自体はリソースに関するキャッシュ情報を知っているかもしれませんが、JavaScriptコードは知りません。その場合、ブラウザーはキャッシュヘッダーを使用して実際の304応答を取得する可能性がありますが、JavaScriptはキャッシュ情報を送信しなかったため、200応答をJavaScriptコードに転送します。

ブラウザで認識されるキャッシュ情報とJavaScriptコードで認識されるキャッシュ情報は予測できない方法で異なる可能性があるため、JavaScript 304リクエストを実際のネットワーク304応答と完全に一致させることはできません。ただし、ほとんどの場合、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レスポンスヘッダーを参照した後に発生します)。

対照的に、このスクリプトはalways 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日にクライアントがどうやら見ていません)。

65
apsillers

また、応答がキャッシュからのものである場合、ヘッダーはキャッシュされます。これをきっかけにしてみました。サーバーが一意の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はハッシュである必要があるため、これは少し乱用されます。

0
B.F.