[英]How to check if jQuery.ajax() request header Status is “304 Not Modified”?
如何检查jQuery.ajax()请求标头状态是否为“ 304未修改”?
即使请求的标头为“ 304 Not Modified”, jqXHR.status
通常也返回200
。
ifModified:true
并没有太大帮助,因为它中断了XHR数据请求。
如果不手动处理高速缓存头,则不可能。 通常, XHR API无法提供304个响应:
对于由于用户代理生成的条件请求而产生的304未修改响应, 用户代理必须像服务器给出200 OK响应并提供适当的内容一样起作用 。
jQuery通常不知道响应是304,因为浏览器告诉JavaScript礼貌的谎言是网络上实际发生的事情。
但是有个好消息:您可以让Ajax产生304响应,但只能通过在请求中手动设置HTTP缓存标头 If-Modified-Since
或If-None-Match
:
用户代理必须允许
setRequestHeader()
通过设置请求标头(例如If-None-Match
,If-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();
一个基本的困难是您如何知道要发送的最后修改日期或ETag ? 该浏览器具有用于发送请求的缓存信息,但不会与JavaScript共享该信息。 幸运的是,jQuery跟踪Ajax响应中的Last-Modified
和ETag
标头,因此您可以使用ifModified:true
使jQuery在下次发送对该资源的请求时设置这些标头值。
需要注意的两件事:
304个响应不携带数据。 这是设计使然。 假设是,如果您选择使用缓存,则应该在缓存中已经有一个数据副本 ! 如果没有从服务器获取数据是一个问题(即,因为您还没有该数据),为什么要使用缓存? 当您手头有旧数据而只需要新数据时,应使用缓存。 因此,使用304取回任何数据应该不是问题。
jQuery必须具有从前一个请求存储的上次修改日期或ETag(用于If-None-Match
)。 过程如下:
首先获取:jQuery没有缓存信息,因此它不会发送If-Modified-Since
或If-None-Match
。 当响应返回时,服务器可以宣布jQuery存储以供将来使用的最后修改的数据或ETag。
后续提取:jQuery具有上一次提取的缓存信息,并将该数据转发到服务器。 如果资源没有更改,则Ajax请求将获得304响应。 如果资源已更改,则Ajax请求将获得200响应,以及jQuery的新缓存信息以用于下一次提取。
但是,jQuery在页面重装之间不会保留缓存信息(例如,在cookie中)。 因此,由于jQuery没有要发送的缓存信息,因此页面重新加载后对资源的首次获取将永远不会是304(即,我们将其重置为“首次获取”的情况)。 jQuery没有理由不能持久化缓存信息,但是目前没有。
最重要的是,您可以使用缓存标头来获取JavaScript 304响应,但是您不能访问浏览器自己的 ETag或特定资源的最后修改日期。 因此,浏览器本身可能知道有关资源的缓存信息,但是您的JavaScript代码却不知道。 在这种情况下,浏览器将使用其缓存标头潜在地获得真实的304响应,但是将200响应转发给您的JavaScript代码,因为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);
运行此服务器时,可以在浏览器中加载页面并在浏览器控制台中执行两个不同的测试:
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
请求标头(服务器的上次修改日期后两天)。 它不依赖于浏览器为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应该是用于验证“解码后的数据与最初发送的数据相同”的哈希。
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,请右键单击并选择检查元素,然后转到“网络”标签。
对于firefox,只需使用firebug并遵循相同的步骤。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.