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

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

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

ifModified:true does not help很多,因为它打破了XHR数据请求。

解决方法

没有手动处理缓存头,这是不可能的。通常,通过 XHR API不能提供304响应:

For 304 Not Modified responses that are a result of a user agent generated conditional request the user agent must act as if the server gave a 200 OK response with the appropriate content.

jQuery通常不知道有一个304响应,因为浏览器告诉礼貌谎言到JavaScript什么实际发生在网络上。

但有一个好消息(种类):你可以获得Ajax产生304响应,但是只有通过手动设置请求中的HTTP cache headers If-Modified-Since或if-none-match

The user agent must allow setRequestHeader() to override automatic cache validation by setting request headers (e.g.,if-none-match,If-Modified-Since),in which case 304 Not Modified responses must be passed through.

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

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

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

有两件事要注意:

> 304响应不携带数据。这是设计。假设如果你选择使用缓存,你应该有一个已经在缓存中的数据的副本!如果从服务器没有数据是一个问题(即,因为你还没有这些数据),为什么要使用缓存?当你拥有旧数据并且只想要新数据时,应该使用缓存;因此,回到304没有数据不应该是一个问题。
> jQuery必须具有从上一个请求存储的最后修改日期或ETag(与if-none-match一起使用)。过程如下:

>第一次抓取:jQuery没有缓存信息,因此它不发送If-Modified-Since或if-none-match。当响应返回时,服务器可以通告最后修改的数据或ETag,jQuery存储以供将来使用。
>后续抓取:jQuery具有来自上次抓取的缓存信息,并将该数据转发到服务器。如果资源没有改变,Ajax请求获得304响应。如果资源已更改,Ajax请求将获得200响应,以及jQuery用于下一次提取的新缓存信息。
>但是,jQuery不会在页面重新加载之间保存缓存信息(例如,在Cookie中)。因此,在页面重新加载之后的资源的第一次提取永远不会是304,因为jQuery没有要发送的高速缓存信息(即,我们重置回“第一次提取”情况)。没有理由为什么jQuery不能保存缓存信息,但目前它不。

这里的底线是,您可以使用缓存头获取JavaScript 304响应,但您无法访问浏览器自己的ETag或上次修改的日期为特定的资源。因此,浏览器本身可能知道有关资源的缓存信息,但是您的JavaScript代码没有。在这种情况下,浏览器将使用其缓存头可能获得真正的304响应,但转发200响应到您的JavaScript代码,因为JavaScript没有发送任何缓存信息。

不可能使JavaScript 304请求与实际的网络304响应完全对齐,因为浏览器已知的缓存信息和JavaScript代码已知的缓存信息可能以不可预测的方式有所不同。然而,大多数时间正确地获得304个请求对于大多数实际开发需要是足够好的。

这里是一个简短的服务器示例,用Node.js编写(但是它应该足够简单,可以端口到其他langauges):

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);

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

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",15 Feb 2013 13:43:19 GMT");
xhr.send();
xhr.onload = function() { console.log(xhr.status); }

脚本提供自己的If-Modified-Since请求头(服务器上次修改日期后两天);它不依赖于浏览器为If-Modified-Since提供的任何内容,因此(根据XHR规范)允许查看304响应。

最后,这个脚本总是会看到200:

var xhr = new XMLHttpRequest();
xhr.open("GET",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日有一个变化,客户端显然没有看到)。

相关文章

页面搜索关键词突出 // 页面搜索关键词突出 $(function () {...
jQuery实时显示日期、时间 html: &lt;span id=&quot...
jQuery 添加水印 &lt;script src=&quot;../../../.....
中文:Sys.WebForms.PageRequestManagerParserErrorExceptio...
1. 用Response.Write方法 代码如下: Response.Write(&q...
Jquery实现按钮点击遮罩加载,处理完后恢复 思路: 1.点击按...