如何检查如果jQuery.ajax()请求标题状态是“304未修改”?

如何检查如果jQuery.ajax()请求标题状态是“304未修改”?

jqXHR.status通常返回200 ,即使请求标头为“304未修改”。

ifModified:true因为它破坏了XHR数据请求,所以没有多大帮助 。

如果不手动处理caching标题,则不可能。 通常,通过XHR API不能提供304个响应:

对于由用户代理生成的条件请求导致的“304未修改”响应, 用户代理必须像服务器给出200 OK响应以及适当的内容那样操作

jQuery通常不知道有一个304响应,因为浏览器告诉礼貌的谎言JavaScript的有关networking上实际发生的事情。

但是有好消息:你可以得到Ajax来产生一个304响应,但是只能通过在请求中手动设置HTTPcaching报头 If-Modified-Since或者If-None-Match

用户代理必须允许setRequestHeader()通过设置请求标头(例如, If-None-MatchIf-Modified-Since )覆盖自动cachingvalidation,在这种情况下必须通过304个未修改的响应。

所以,你可以使用如下代码:

 var xhr = new XMLHttpRequest(); xhr.open("GET", "foo.html"); xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT"); xhr.send(); 

一个根本的难点是你怎么知道最后修改date或ETag发送? 浏览器具有用于发送请求的caching信息,但不会与JavaScript共享该信息。 幸运的是,jQuery跟踪来自Ajax响应的Last-ModifiedETag头,因此您可以使用ifModified:true来让jQuery在下次发送对该资源的请求时设置这些头值。

有两点需要注意:

  • 304个回复不包含数据。 这是devise。 假设是,如果你select使用caching,你应该有一个已经在你的caching中的数据的副本 ! 如果没有从服务器获取数据是一个问题(即,因为你还没有这些数据),为什么你使用caching? 当你手头有旧的数据,只需要新的数据时,应该使用caching。 因此,回到304没有数据不应该是一个问题。

  • jQuery必须有一个最后修改的date或一个ETag(与If-None-Match一起使用)从前一个请求中存储。 过程如下所示:

    • 首先获取:jQuery没有caching信息,所以它不会发送If-Modified-SinceIf-None-Match 。 当响应返回时,服务器可能会发布最后修改的数据或ETag,jQuery存储以供将来使用。

    • 后续提取:jQuery有来自上次获取的caching信息,并将该数据转发给服务器。 如果资源没有改变,Ajax请求会得到一个304响应。 如果资源发生了变化,Ajax请求将获得200响应,以及jQuery的新caching信息以用于下一次获取。

    • 但是,jQuery 不会在页面重新加载之间持久化caching信息(例如,在cookie中)。 因此,页面重新加载之后首次获取资源将永远不会是304,因为jQuery没有要发送的caching信息(即,我们重置为“第一次获取”情况)。 没有理由为什么jQuery 不能坚持caching信息,但目前它没有。

这里的底线是您可以使用caching标头来获得JavaScript 304响应,但是您无法访问浏览器自己的 ETag或特定资源的上次修改date。 所以,浏览器本身可能知道关于资源的caching信息,但是你的JavaScript代码却不知道。 在这种情况下,浏览器将使用它的caching标头来获得一个真实的304响应,但是会将一个200响应转发给你的JavaScript代码,因为JavaScript没有发送任何caching信息。

由于浏览器已知的caching信息和JavaScript代码已知的caching信息可能以不可预知的方式不同,因此不可能使JavaScript 304请求与实际的networking304响应完全alignment。 但是,大多数情况下正确获得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); 

运行此服务器时,可以在浏览器中加载页面,并在浏览器控制台中执行两个不同的testing:

 var xhr = new XMLHttpRequest(); xhr.open("GET", "/"); xhr.send(); xhr.onload = function() { console.log(xhr.status); } 

即使浏览器提供了一个If-Modified-Since请求头并获得一个304 (在浏览器看到服务器的Last-Modifed响应头之后,将在第一个请求之后发生所有请求),该脚本始终会看到200响应。

相比之下,这个脚本总是会看到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请求头(服务器的最后修改date后两天); 它不依赖于浏览器为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 ,它在服务器的最后修改date之前,所以服务器总是发送一个200 。 服务器不会发送304因为它假定客户端没有最新版本的caching副本(即客户端宣布自2月12日以来发生更改,但是在2月13日发生了变化,客户端显然还没有见过)。

此外,如果响应来自caching,则标头将被caching。 我把这当成了一个机会。 我的服务器发送一个唯一的md5头。 这有不一样的效果像?query = time()。 现在在JS端validation最新的md5头与当前。 如果您收到的响应来自caching,则返回与之前相同的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应该是一个散列,以validation“解码的数据是最初发送相同的数据”。

我有一种在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 } }); 

打开你的浏览器检查器,它会告诉你关于ajax请求的信息,包括状态。

对于chrome,右键单击并select检查元素,然后转到networking选项卡。

对于Firefox,只需使用萤火虫,并按照相同的步骤。