ajax中的cache问题
日期:2008-11-11 阅读:258 分类:Javascript
如何避免IE的XmlHttpRequest Cache?
前一段时间,我写过一个动态桌面,我想要在桌面动态显示slashdot的RSS新闻,这样每次我返回桌面的瞬间里,总可以瞥到一些即时的讯息。没办法,已经深陷资讯时代的陷阱。
我的代码如下(使用prototype 1.3.1):
var options = {
asynchronous: true,
method: "GET",
onSuccess: function(http) {
var newsXml = http.responseXML;
//handle news items
..............
}.bind(this)
};
new Ajax.Request(url, options);
但事非所愿,几天过后,我发现还总是在看到几天前的新闻,而slashdot的新闻怎么可能更新如此缓慢呢?猛然,我想到了IE的 Cache 问题。几天的探索,我修正了我的代码,也有了一番心得。
首先,大家不妨使用IE测试一下如下代码:
〈textarea rows="10" cols="80" id="output"〉〈/textarea〉
〈script language="javascript"〉
function sendRequest(url) {
req = new ActiveXObject("Microsoft.XMLHTTP");
req.open("GET",url,true);
writeStuff(’Opening ’ + url);
req.onreadystatechange = function () {
writeStuff(’readyState is now ’ + req.readyState);
}
req.send(null);
writeStuff(’Sending request’);
}
function writeStuff(msg) {
document.getElementById("output").value += msg + "\\r\\n";
}
sendRequest("http://www.google.com";);
〈/script〉
第一次运行的时候,output 输出是正常的
Opening http://www.google.com ;
readyState is now 1
Sending request
readyState is now 2
readyState is now 3
readyState is now 4
可当你刷新再执行之后,output 输出变成了这样
Opening http://www.google.com ;
readyState is now 1
readyState is now 2
readyState is now 3
readyState is now 4
Sending request
也就是说,当IE从本地Cache而非远程获取数据的时候,onreadystatechange事件处理器在发送请求前就已经先执行完成了。如果再配合sniffer工具,你会发现,IE根本就没有真正向远程网络发送请求。
这也就解释了我之所以总是看到旧新闻的原因。
参照 ajaxpatterns上的建议,我修改了我的代码:
var options = {
asynchronous: true,
method: "GET",
onSuccess: function(http) {
//保存lastModified 到一个变量
lastModified = http.getResponseHeader("Last-Modified");
var newsXml = http.responseXML;
//handle news items
..............
}.bind(this)
};
if (lastModified)
//prototype将执行 request.setRequestHeader("If-Modified-Since", lastModified)
options.requestHeaders = ["If-Modified-Since", lastModified];
else
url += (url.indexOf("?")==-1?"?":"&") + "timestamp=" + new Date().getTime();
new Ajax.Request(url, options);
这样,每次处理RSS返回数据的时候,我都记录"Last-Modified" Header的时间,而在下一次发送请求前,把这个最后修改时间设置给"If-Modified-Since" Request Header。"If-Modified-Since" Header 会提示服务器只在Header设置的时间后页面有更新的情况下才返回数据。配合sniffer工具,发现此时RSS服务器除了简单的返回一个304状态值(没有更新数据),不再返回旧的RSS数据。这样的效果也可以有效的节约无谓的网络数据传输。
当然,不同的web服务器对Http Header 的支持与处理方式不同。有些服务器可能并不返回"Last-Modified" Header,或者不支持"If-Modified-Since" Header。那我们还可以使用被广泛采用的方法:给URL增加一个唯一ID以欺骗IE重新访问远程数据。如上代码中我给url加了一个当前的时间戳。
前面所言的只是客户端的所可以做的避免cache的努力,当我们自己编写Ajax应用的时候,如果要追求最保险的避免cache方案,我们还需要结合服务端程序来设置避免cache的Response Header,比如如下的PHP代码:
header("Expires: Sat, 1 Jan 2005 00:00:00 GMT");
header("Last-Modified: ".gmdate( "D, d M Y H:i:s")."GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
另外需要补充说明的几点
IE 的 XmlHttpRequest Cache 问题只有在GET方式的时候才发生,POST方式根据http 协议不会产生cache的问题,但千万不要以为把GET改成POST也可以解决cache的问题。不相信的话,可以试试用POST方式访问下google的首页。
FireFox的XmlHttpRequest对象没有cache问题,Firefox每次发送XmlHttpRequest的时候,都会自动加上取消cache的Http Header。
cache 对XmlHttpRequest也并非全无是处,恰恰相反,正确的使用cache可以改善web应用的效率。我以为cache的管理将是Ajax框架的一个重要组成部分。但象IE这样自作主张的方式惹人讨厌。
前一段时间,我写过一个动态桌面,我想要在桌面动态显示slashdot的RSS新闻,这样每次我返回桌面的瞬间里,总可以瞥到一些即时的讯息。没办法,已经深陷资讯时代的陷阱。
我的代码如下(使用prototype 1.3.1):
var options = {
asynchronous: true,
method: "GET",
onSuccess: function(http) {
var newsXml = http.responseXML;
//handle news items
..............
}.bind(this)
};
new Ajax.Request(url, options);
但事非所愿,几天过后,我发现还总是在看到几天前的新闻,而slashdot的新闻怎么可能更新如此缓慢呢?猛然,我想到了IE的 Cache 问题。几天的探索,我修正了我的代码,也有了一番心得。
首先,大家不妨使用IE测试一下如下代码:
〈textarea rows="10" cols="80" id="output"〉〈/textarea〉
〈script language="javascript"〉
function sendRequest(url) {
req = new ActiveXObject("Microsoft.XMLHTTP");
req.open("GET",url,true);
writeStuff(’Opening ’ + url);
req.onreadystatechange = function () {
writeStuff(’readyState is now ’ + req.readyState);
}
req.send(null);
writeStuff(’Sending request’);
}
function writeStuff(msg) {
document.getElementById("output").value += msg + "\\r\\n";
}
sendRequest("http://www.google.com";);
〈/script〉
第一次运行的时候,output 输出是正常的
Opening http://www.google.com ;
readyState is now 1
Sending request
readyState is now 2
readyState is now 3
readyState is now 4
可当你刷新再执行之后,output 输出变成了这样
Opening http://www.google.com ;
readyState is now 1
readyState is now 2
readyState is now 3
readyState is now 4
Sending request
也就是说,当IE从本地Cache而非远程获取数据的时候,onreadystatechange事件处理器在发送请求前就已经先执行完成了。如果再配合sniffer工具,你会发现,IE根本就没有真正向远程网络发送请求。
这也就解释了我之所以总是看到旧新闻的原因。
参照 ajaxpatterns上的建议,我修改了我的代码:
var options = {
asynchronous: true,
method: "GET",
onSuccess: function(http) {
//保存lastModified 到一个变量
lastModified = http.getResponseHeader("Last-Modified");
var newsXml = http.responseXML;
//handle news items
..............
}.bind(this)
};
if (lastModified)
//prototype将执行 request.setRequestHeader("If-Modified-Since", lastModified)
options.requestHeaders = ["If-Modified-Since", lastModified];
else
url += (url.indexOf("?")==-1?"?":"&") + "timestamp=" + new Date().getTime();
new Ajax.Request(url, options);
这样,每次处理RSS返回数据的时候,我都记录"Last-Modified" Header的时间,而在下一次发送请求前,把这个最后修改时间设置给"If-Modified-Since" Request Header。"If-Modified-Since" Header 会提示服务器只在Header设置的时间后页面有更新的情况下才返回数据。配合sniffer工具,发现此时RSS服务器除了简单的返回一个304状态值(没有更新数据),不再返回旧的RSS数据。这样的效果也可以有效的节约无谓的网络数据传输。
当然,不同的web服务器对Http Header 的支持与处理方式不同。有些服务器可能并不返回"Last-Modified" Header,或者不支持"If-Modified-Since" Header。那我们还可以使用被广泛采用的方法:给URL增加一个唯一ID以欺骗IE重新访问远程数据。如上代码中我给url加了一个当前的时间戳。
前面所言的只是客户端的所可以做的避免cache的努力,当我们自己编写Ajax应用的时候,如果要追求最保险的避免cache方案,我们还需要结合服务端程序来设置避免cache的Response Header,比如如下的PHP代码:
header("Expires: Sat, 1 Jan 2005 00:00:00 GMT");
header("Last-Modified: ".gmdate( "D, d M Y H:i:s")."GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
另外需要补充说明的几点
IE 的 XmlHttpRequest Cache 问题只有在GET方式的时候才发生,POST方式根据http 协议不会产生cache的问题,但千万不要以为把GET改成POST也可以解决cache的问题。不相信的话,可以试试用POST方式访问下google的首页。
FireFox的XmlHttpRequest对象没有cache问题,Firefox每次发送XmlHttpRequest的时候,都会自动加上取消cache的Http Header。
cache 对XmlHttpRequest也并非全无是处,恰恰相反,正确的使用cache可以改善web应用的效率。我以为cache的管理将是Ajax框架的一个重要组成部分。但象IE这样自作主张的方式惹人讨厌。
相关文章
- ajax跨域请求问题解决方案(2) 2009-02-25
- Ajax优于JSF的几个原因讨论 2008-07-28
- 非常简练的ajax操作函数 2008-10-28
- ajax跨域请求问题解决方案(1) 2009-01-23
- Script方式实现Ajax在IE9下的一个问题 2011-12-22
网友评论
#1: 2008-11-11 14:09:00 by kj
学习了