强制浏览器清除缓存

361

有没有一种方法可以在我的网页上放置一些代码,以便当有人访问该网站时,清除浏览器缓存,这样他们就可以查看更改内容了?

使用的语言:ASP.NET,VB.NET以及HTML,CSS和jQuery。


一个不错的“清除缓存”的解决方案或变通方法可以在这里找到:https://dev59.com/nWsz5IYBdhLWcg3wBzfi#43676353 - caramba
2023年,您可以使用Clear-Site-Data HTTP头部;有关详细信息,请参阅此答案 - undefined
23个回答

438

如果涉及到 .css.js 文件的更改,一种方法是通过为每个发布版本在文件名末尾添加类似于 "_versionNo" 的字符串来进行“缓存清除”。例如:

script_1.0.css // This is the URL for release 1.0
script_1.1.css // This is the URL for release 1.1
script_1.2.css // etc.
或在文件名后面:
script.css?v=1.0 // This is the URL for release 1.0
script.css?v=1.1 // This is the URL for release 1.1
script.css?v=1.2 // etc.
你可以查看这个链接,了解它如何工作。

15
这是一个相当不错的解决方案,甚至可以由您的构建系统自动化(而且应该这样做)。例如,Stackoverflow就采用了这种方法。 - derobert
8
SO现在正在使用GET参数。 - Saeb Amini
78
更好的做法是保持文件名不变,但是在文件名后面添加版本号作为查询字符串参数,例如 script.js?v=1.2。(或者如果你没有跟踪版本,只需使用文件的最后修改时间,这更容易实现)。不确定前面的评论者是否是指这个方法! - Doin
8
大家是如何使用版本控制的?看起来非常繁琐。 - Shawn
3
@Doin,我简要测试了该技术,似乎可以完全防止Firefox和Chrome缓存文件。 - Sam
显示剩余12条评论

128

查看 缓存控制过期 META 标签。

<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="2002年7月22日 星期一 11:12:01 GMT">

另一个常见的做法是在请求的文件结尾添加不断改变的字符串。例如:

<script type="text/javascript" src="main.js?v=12392823"></script>


60
如果内容已经被缓存,这并不能帮助太多——因为它已经被缓存,服务器不会被查询,因此无法响应no-cache。此外,正如注释所说,这个meta标签真的不应该被使用,因为它会与Web缓存发生冲突。 - derobert
1
+1 顶derobert所说的。最好始终使用HTTP头来建议客户端和Web缓存的缓存策略,但即使如此,也无法强制重新加载缓存。 - user213154
5
对于你的第二个解决方案我给予赞同(+1)。我的问题是当管理员进行更新后,缓存应该仅在第一次被清除。该方法可以解决这个问题。 - Jules Colle
1
完全禁用缓存通常是一个非常糟糕的想法。 - Jordan
1
我是一个初学者,但我注意到以下MDN Cache-Control文档:“如果您不想将响应存储在任何缓存中,请使用no-store。该指令无法防止缓存存储您的响应。” 但是当我在这个页面上搜索“no-store”时,似乎没有人提到它。我一定是误解了什么,那是什么? - Matt Groth

80

2012年更新

这是一个旧问题,但我认为它需要更加现代的答案,因为现在有一种方法可以更好地控制网站缓存。

离线Web应用程序(实际上是任何HTML5网站)中,可以使用applicationCache.swapCache()来更新您网站的缓存版本,而无需手动重新加载页面。

这是来自HTML5 Rocks应用缓存入门指南的代码示例,解释了如何将用户更新到您网站的最新版本:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

  window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
      // Browser downloaded a new app cache.
      // Swap it in and reload the page to get the new hotness.
      window.applicationCache.swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);

}, false);

2016更新

Web技术发展迅速。

这个问题是在2009年提出的,2012年我发布了一个有关该问题描述的新方法。又过了4年,现在看来它已经被弃用了。感谢cgaldiolo在评论中指出这一点。

截至2016年7月,HTML标准第7.9节“离线Web应用”包含一个废弃警告:

此功能正在从Web平台中删除。 (这是一个需要多年时间的漫长过程。)目前高度不建议使用任何离线Web应用功能。 相反,应使用服务工作者。

所以,我在2012年提到的Mozilla开发者网络上的应用缓存使用也是如此:

已弃用
此功能已从Web标准中删除。 虽然某些浏览器仍可能支持它,但它正在被删除过程中。不要在旧项目或新项目中使用它。使用它的页面或Web应用程序随时可能会崩溃。

另请参见Bug 1204581 - 如果启用服务工作者获取拦截,请添加有关AppCache的弃用通知

另请参见Mozilla开发者网络上的应用缓存使用以获取更多信息。


1
这是否意味着您需要使用和维护缓存清单文件? - Sam
79
截至2017年,目前的建议是什么? - Garrett
5
2017年:使用Service Workers。 - digitai
@rsp,你知道最新的答案吗?不使用已弃用的API? - trusktr
6
2021年有任何推荐吗? - Anonymous Y - 杨z强
显示剩余6条评论

27

并不是这样的。一种方法是在传递内容时发送适当的头信息,以强制浏览器重新加载:

确保网页在所有浏览器中不被缓存。

如果您在SO上搜索“cache header”或类似的内容,您将找到ASP.NET特定的示例。

另一种不太干净但有时是唯一的方法(如果无法控制服务器端的头信息),是向调用的资源添加一个随机的GET参数:

myimage.gif?random=1923849839

3
最好对文件进行适当的版本控制。否则会浪费大量带宽并且更重要的是会让网站变得非常慢。 - derobert
8
这实际上取决于情况,对吧?如果你正在编写一个内容管理系统(CMS),并需要确保所有更改的资源得到正确更新,有时候这两个选项之一是必须的。 - Pekka
这样的解决方案应该被投票否决。我们有责任尽可能地降低互联网的二氧化碳排放量。 - timing
1
正如@derobert所说,这完全浪费带宽并且会减慢页面加载速度,因为每次刷新都会强制客户端重新加载资源,即使它没有改变,更好的方法是对文件进行哈希处理,并将其作为查询参数发送,这样只有在文件更改时才会更改。 - Ako

17

我遇到了类似的问题,以下是我的解决方法:

  1. index.html文件中,我添加了清单文件:

    <html manifest="cache.manifest">
    
  2. <head> 部分包含更新缓存的脚本:

  3. <script type="text/javascript" src="update_cache.js"></script>
    
    <body>部分,我插入了一个onload函数:
    <body onload="checkForUpdate()">
    
  4. cache.manifest中,我已经放置了我想要缓存的所有文件。现在重要的是,它在我的情况下(Apache)只需每次更新“版本”注释即可正常工作。另外,将文件命名为带有“?ver=001”或类似结尾的东西也是一种选择,但不是必需的。只需更改# version 1.01就会触发缓存更新事件。

  5. CACHE MANIFEST
    # version 1.01
    style.css
    imgs/logo.png
    #all other files
    

    在index.html中仅仅包含1、2和3点是很重要的。否则。

    GET http://foo.bar/resource.ext net::ERR_FAILED
    

    发生这种情况是因为每个“子”文件在页面已经被缓存的同时尝试缓存该页面。

  6. update_cache.js文件中,我放置了以下代码:

    function checkForUpdate()
    {
        if (window.applicationCache != undefined && window.applicationCache != null)
        {
            window.applicationCache.addEventListener('updateready', updateApplication);
        }
    }
    function updateApplication(event)
    {
        if (window.applicationCache.status != 4) return;
        window.applicationCache.removeEventListener('updateready', updateApplication);
        window.applicationCache.swapCache();
        window.location.reload();
    }
    
    现在你只需要更改文件,在清单中更新版本注释。现在访问index.html页面将更新缓存。
    这个解决方案的部分不是我自己的,而是我通过互联网找到并组合起来使其工作。

1
Shweta Gulati,清单文件应该与“index”文件在同一个文件夹中。有哪些情况下它不起作用? - Wojtek Mazurek
1
@ShwetaGulati 是的,缓存不会检测HTML文件中的更改 - 这就是为什么您必须在清单文件中更新版本号的原因,因为正在检查此文件以查看更改。我很难帮助您,因为我不知道详细情况。请告诉我是否已将所有要缓存的文件放在清单中?路径应相对于清单文件。您可以给我您网站的地址,我可以告诉您出了什么问题 :) - Wojtek Mazurek
2
@ShwetaGulati 这是因为浏览器会自动缓存一些文件以加快页面加载速度。这是默认行为,完全取决于浏览器,所以您无法以任何方式设置它。特别是 js 文件的范围在于浏览器,因为它们通常用于网站上的所有页面,因此缓存它们是明智的选择。除了将所有文件的名称编写到清单文件中以缓存所有文件外,没有其他方法。如果您找到了其他方法,请告诉我,因为我也需要 :) - Wojtek Mazurek
1
你的文件的绝对路径并不重要,相对路径才重要,因为浏览器会发送文件请求。例如:我有一个域名example.com,它在服务器names.com上。我的空间是example.names.com。所以我将我的example.com域名连接到我的服务器空间example.names.com作为重定向。为此,我需要将文件夹设置为此重定向的目标。因此,如果我想在example.names.com上拥有几个站点,我创建文件夹"name1",将其重定向到该文件夹,并放置所有文件。路径从这里开始计算。如果我在清单文件中有name1\scripts\test.js,则写入scripts\test.js。 - Wojtek Mazurek
2
为了以后的参考,浏览器已经移除/弃用/禁用了这个功能。 - Luis Alvarado
显示剩余8条评论

15

对于静态资源来说,正确的缓存方式是使用查询参数,并将值设置为每个部署或文件版本的版本号。这将在每次部署后清除缓存。

/Content/css/Site.css?version={FileVersionNumber}

这里是ASP.NET MVC的例子。

<link href="@Url.Content("~/Content/Css/Reset.css")?version=@this.GetType().Assembly.GetName().Version" rel="stylesheet" type="text/css" />

不要忘记更新程序集版本。


1
谢谢您的回答,但是当我们在BundleTable中添加资源时,应该如何做呢? - toregua
1
在我的情况下,这会返回版本号为“0.0.0.0”。 要获取MVC应用程序的dll版本,请改用以下方法: ?version=@ViewContext.Controller.GetType().Assembly.GetName().Version - CGodo
2
我发现这可以防止Firefox和Chrome完全缓存内容。 - Sam

8

从2023年开始

目前,许多网络浏览器都支持使用 Clear-Site-Data HTTP 头部 [MDN 参考]。为了指示客户端的网络浏览器清除网站域名和子域名的缓存,请在来自服务器的 HTTP 响应中设置以下头部:

Clear-Site-Data: "cache"

或者,以下标头可能在各种浏览器中得到更好的支持,但它除了缓存之外还会清除其他网站数据,例如localStorage和cookies。

Clear-Site-Data: "*"

然而请注意,中间缓存(例如CDN)可能无法理解或尊重此标头,因此中间缓存仍可能响应以前缓存的数据。


7

我曾经遇到一个问题,就是在网上为客户拍照之后,需要更新div,但浏览器仍然显示旧的照片。所以我使用了一种方法来调用随机GET变量,这将每次都是唯一的。如果有帮助,以下是代码:

<img src="/photos/userid_73.jpg?random=<?php echo rand() ?>" ...

编辑 正如其他人指出的那样,以下是更高效的解决方案,因为它只会在图像更改时重新加载图像,并通过文件大小识别此更改:

<img src="/photos/userid_73.jpg?modified=<? filemtime("/photos/userid_73.jpg")?>"

35
这样做一点也不优雅,会导致网站每次重新加载图像,浪费大量时间下载资源。更好的解决方案是使用 filesize 而不是随机数,这样只有在文件实际更改时才会重新验证缓存。 - Roberto Arosemena
9
图片字节的哈希值。 - Taylor D. Edmiston
1
这完全取决于用户的需求。对于大量照片的情况,情况会与少量照片不同。检查文件大小可以节省带宽,但也会增加额外的处理,可能会减慢页面加载速度。在我的情况下,图片变化非常频繁,而且用户能够获取最新的图片是至关重要的商业决策,因此这是一个完美的解决方案。 - zeeshan
这绝不是一个完美的解决方案... @Seer建议的简单但更好的方法是只有在实际更改照片时才更改值(从而强制浏览器获取新照片)! - Bruce
3
<img src="/photos/userid_73.jpg?modified=<?= filemtime("/photos/userid_73.jpg") ?>" 这样会更有用! - Fusca Software
显示剩余5条评论

5
更新URL为以下内容对我有效:
/custom.js?id=1
通过在“?id=”后添加唯一数字并针对新更改递增它,用户无需按下“CTRL + F5”来刷新缓存。或者,您可以在“?id=”后附加当前时间或Epoch的哈希或字符串版本。
类似于?id=1520606295

4
很多答案都没有抓住重点——大多数开发人员都知道关闭缓存是低效的。然而,在许多常见情况下,效率并不重要,而默认缓存行为则非常糟糕。这些情况包括嵌套的、迭代的脚本测试(最大的问题!)和损坏的第三方软件解决方法。这里提供的解决方案都无法解决这些常见情况。大多数网络浏览器都过于积极地缓存,并且没有明智的方法来避免这些问题。

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