防止浏览器缓存AJAX调用结果

289

看起来如果我使用$.get()加载动态内容,结果会被浏览器缓存。

在查询字符串中添加一些随机字符串似乎可以解决此问题(我使用new Date().toString()),但这感觉像是一个hack。

是否有其他方法可以实现这一点? 或者,如果唯一的方法是使用唯一字符串,除了new Date()之外还有什么建议吗?


你可以使用简短的符号 $.now() 代替每次都执行 (new Date().getTime())。 - epicwhale
4
你是否考虑选另一个答案作为被采纳的答案? - M4N
21个回答

544
以下内容可以防止所有未来的 AJAX 请求被缓存,无论您使用哪种 jQuery 方法(例如 $.get、$.ajax 等)。
$.ajaxSetup({ cache: false });

7
经过调查(使用 Fiddler),看起来 jQuery 内部实现是通过简单地附加时间戳来实现这一点(正如在其他答案中讨论的)。在我看来,.ajaxSetup 方法更为简洁(个人认为)。 - Peter J
8
确实不需要在“文档准备就绪”调用内部。 - Peter J
21
为什么要全局禁用ajax缓存?我认为应该在每个调用的基础上进行控制,就像Jonathan的回答所做的那样。 - Sunny R Gupta
6
无论你的应用程序需要什么样的方式,都可以采用。在商业应用中,当我绝对需要所有AJAX调用的新数据时,我仍然使用这种方法。对于其他情况,缓存数据也是可以接受的。 - Peter J
1
描述:为未来的Ajax请求设置默认值。不建议使用它。 - itwebdeveloper
显示剩余10条评论

358
JQuery的$.get()会缓存结果。可以使用$.ajax()代替,将cache参数设置为false,以防止结果被缓存。
$.get("myurl", myCallback)

你应该使用$.ajax,这将允许你关闭缓存:

$.ajax({url: "myurl", success: myCallback, cache: false});

72
这是正确答案,我认为Peter J全局禁用缓存的方法是不良实践。 - salmatron
8
需要注意的是,这里的“全局”仅限于页面/请求范围内。 - Peter J
3
缓存应该根据请求类型进行特定设置。某些服务器请求可能需要缓存(其中服务器数据是静态的),因此选择在每个请求的基础上进行缓存比关闭所有缓存更好。 - iCollect.it Ltd
2
另一个好答案。我必须说,对我来说,大多数情况下全局禁用缓存都非常有益。不过这完全取决于你的应用程序是如何设计的。没有银弹,但在这种情况下,我建议使用一个接受布尔值进行缓存、回调函数和URL的函数来实现模块化。手动“hack”也可以,但如果你正在使用jQuery,请尽可能使用它们的函数。这不仅会使开发更容易,而且还会使将来升级库更加容易。 - Anthony Mason
3
“JQuery的$.get()会缓存结果”并不是严格正确的说法;实际上是浏览器可能决定使用缓存的结果,而不是jQuery。当使用$.ajaxcache: false时,jQuery会在URL中附加时间戳,以确保从服务器获取新的响应结果。 - DigitalDan
显示剩余2条评论

250

我使用new Date().getTime(),它会避免冲突,除非在同一毫秒内发生多个请求:

$.get('/getdata?_=' + new Date().getTime(), function(data) {
    console.log(data); 
});

编辑: 这个答案已经几年了,它仍然有效(因此我没有删除它),但现在有更好/更清洁的方法来实现这一点。 我更喜欢这种方法,但这个答案也很有用,如果你想在页面的生命周期内禁用每个请求的缓存。


16
我会点踩,因为像 Peter J. 的回答一样让 jQuery 处理会更加简洁。你的解决方案也可以工作,但从长远来看会更难维护。 - Niklas Wulff
14
需要维护的部分是什么?与jQuery相比有何不同? - Sunny R Gupta
5
值得注意的是,new Date().getTime()代码被用来这样写... var nocache = new Date().getTime(); var path = 'http://hostname.domain.tld/api/somejsonapi/?cache=' + nocache;。我自己花了几分钟才弄明白这个。当然,?cache可以是API实际不想要的任何词语。 - doubleJ
1
即使Peter J的答案有更好的方法,+1 even这个答案既不是错误的,也不是一个糟糕的答案。我相信DV是因为你的回答排在Peter的上面(作为被接受的答案)。而且OP自2013年初以来就没有出现在SO上了。 - Michel Ayres
1
url = url + (-1 === url.indexOf('?') ? '?' : '&') + "__=" + Number(new Date()); - user257319
显示剩余3条评论

32

这里所有的答案都会在服务器的访问日志中留下请求URL的足迹。

我需要一个基于头部的解决方案,没有副作用,我发现可以通过设置如何控制所有浏览器上网页缓存?中提到的标头来实现。

至少对于Chrome而言,结果如下:

$.ajax({
   url: url, 
   headers: {
     'Cache-Control': 'no-cache, no-store, must-revalidate', 
     'Pragma': 'no-cache', 
     'Expires': '0'
   }
});


1
也许是一个愚蠢的问题,但如果我的 ajax 返回图像,那么这些图像会被缓存吗?以避免大量请求 Amazon S3? - Marcelo Agimóvel
3
现在是2022年,只有这种方法对我有效——使用ASP.Net Core应用程序并在Chrome上进行测试。 - Xequtor
我认为这取决于浏览器是否遵守这个请求。我在某处读到IE忽略了no-cache指令,所以对我来说,我相信添加时间戳的概念会很好。来源:https://dev59.com/GHVC5IYBdhLWcg3wlyQo#244931 - Karue Benson Karue

24

另一种方法是在生成响应请求的代码中,从服务器端提供无缓存头部信息:

response.setHeader( "Pragma", "no-cache" );
response.setHeader( "Cache-Control", "no-cache" );
response.setDateHeader( "Expires", 0 );

17
错误。在IE中,针对XMLHttpRequest调用忽略了no-cache头,详见此处:https://dev59.com/GHVC5IYBdhLWcg3wlyQoDateTime(或我的.ajaxSetup方法)是唯一真正可行的解决方案。 - Peter J
我刚刚粘贴了我的常规无缓存口令,没有说明它是IE特定的。 - miceuz
2
这将关闭所有浏览器的缓存:response.setHeader("Cache-Control", "max-age=0,no-cache,no-store,post-check=0,pre-check=0"); - Chris Broski

18

按照文档要求:http://api.jquery.com/jquery.ajax/

您可以使用cache属性:

$.ajax({
    method: "GET",
    url: "/Home/AddProduct?",
    data: { param1: value1, param2: value2},
    cache: false,
    success: function (result) {
        // TODO
    }
});

14

个人认为使用查询字符串方法比在服务器上设置标头更可靠 - 没有保证代理或浏览器不会缓存它(一些浏览器比其他浏览器更糟糕,不点名)。

我通常使用 Math.random(),但是我认为使用日期也没有问题(你不应该频繁发起AJAX请求以获取相同的值两次)。


2
将Date().getTime()与Math.random()组合在一起,你就应该安全了。另外,值得一提的是,当指定disableCaching时,Ext.Ajax也使用getTime()函数。 - vividos

6
当然,“缓存破坏”技术可以完成工作,但如果服务器向客户端指示响应不应该被缓存,这种情况就不会发生。在某些情况下,缓存响应是有益的,而有时则不是。让服务器决定数据的正确生命周期。您可能希望稍后更改它。从服务器更容易做到这一点,而不是从UI代码的许多不同位置进行更改。
当然,如果您无法控制服务器,则此方法无济于事。

6
真正的问题是为什么您需要这个资源不被缓存。如果它不应该被缓存,因为它经常更改,那么服务器应该指定不要缓存该资源。如果它只是偶尔更改(因为它依赖的某些资源可能会更改),并且如果客户端代码有一种了解它的方法,它可以将一个虚拟参数附加到url中,该虚拟参数从这些资源的某个哈希或上次修改日期计算而来(这就是我们在Microsoft Ajax脚本资源中所做的,因此它们可以永久缓存,但新版本仍然可以随时提供)。如果客户端无法知道更改,则正确的方法应该是让服务器正确处理HEAD请求,并告诉客户端是否使用缓存版本。 对我来说,添加随机参数或从客户端告知不要缓存似乎是错误的,因为可缓存性是服务器资源的属性,因此应该由服务器端决定。 另一个需要考虑的问题是这个资源真的应该通过GET提供还是应该通过POST提供?这是一个语义问题,但它也具有安全性影响(只有在服务器允许GET时才会发生攻击)。POST不会被缓存。

8
如果您正在使用您无法控制其缓存策略的代理服务器,该怎么办?如果您的应用程序明确需要每次都进行新请求,该怎么办?事情的答案并不总是明确的黑白分明,总会有灰色地带。 - 7wp
没错,事情并不总是那么明确。但看到这个答案让我质疑了我的假设,并帮助我找到了问题的根本原因。这可能不适用于每个人,但对我有所帮助。如果你在阅读这篇文章,你也应该考虑一下。 - Jonathan Tran
这确实帮了我,ResponseCaching默认在服务器端设置为60分钟。将其更改为No-Cache后,客户端停止缓存。 - mattygee

5
也许你应该考虑使用$.ajax()(如果你正在使用jQuery的话,这似乎是你正在做的)。 看一下:http://docs.jquery.com/Ajax/jQuery.ajax#options和选项“cache”。 另一个方法是查看如何在服务器端缓存东西。

1
不幸的是,在进行了一些调查后,使用$.ajax()和设置cache = false基本上会做同样的事情。jQuery将向查询字符串添加一些随机数,并且它不会检查现有的查询字符串。所以我想使用$.get()就足够了。 - Salamander2007
啊,好的。我从来没有尝试过,只是记得在文档中看到过相关内容 :) - finpingvin
甚至不需要使用$.ajax。只需使用.ajaxSetup即可。 - Peter J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接