【问题标题】:Force browser to clear cache强制浏览器清除缓存
【发布时间】:2016-02-18 13:34:54
【问题描述】:

有没有办法可以在我的页面上放置一些代码,这样当有人访问网站时,它会清除浏览器缓存,以便他们可以查看更改?

使用的语言:ASP.NET、VB.NET,当然还有 HTML、CSS 和 jQuery。

【问题讨论】:

标签: html caching browser meta-tags


【解决方案1】:

如果这是关于 .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.

您可以查看此link 以了解它是如何工作的。

【讨论】:

  • 这是一个相当不错的解决方案,甚至可以由您的构建系统自动化(并且应该是)。例如,Stackoverflow 就使用了这种方法。
  • SO 现在正在使用 GET 参数。
  • 更好的是保持文件名原样,但将版本号附加为查询字符串参数,即script.js?v=1.2。 (或者,如果您不跟踪版本,只需使用文件上次修改时间,这更容易做到)。不知道前面的评论是不是这个意思!
  • 大家是如何通过版本控制做到这一点的?似乎真的很痛苦。
  • @Doin,我简要测试了该技术,它似乎可以阻止 Firefox 和 Chrome 完全缓存文件。
【解决方案2】:

查看cache-controlexpires META 标签。

<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="Mon, 22 Jul 2002 11:12:01 GMT">

另一种常见做法是将不断变化的字符串附加到请求文件的末尾。例如:

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

【讨论】:

  • 这在它已经被缓存的情况下没有多大帮助——因为它被缓存了,服务器将不会被查询,因此无法响应 no-cache。此外,确实不应该使用该元标记,正如注释所说,它会破坏网络缓存。
  • +1 德罗伯特所说的。使用 HTTP 标头向客户端和 Web 缓存建议缓存策略总是更好,但即使这样也不能强制缓存重新加载。
  • +1 为您的第二个解决方案。我有这个问题,缓存应该只在某些管理员进行更新后第一次被清除。这种方法应该可以解决这个问题
  • 完全禁用缓存通常是一个非常糟糕的主意。
  • 我是初学者,但我注意到MDN Cache-Control doc 的以下内容:“如果您的意思是不将响应存储在任何缓存中,请改用 no-store。该指令无法有效防止缓存存储您的响应。”但是当我在这个页面搜索“no-store”时,似乎没有人提到它。我一定是误会了什么,这是什么?
【解决方案3】:

2012 年更新

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

Offline Web Applications(实际上是任何 HTML5 网站)中,applicationCache.swapCache() 可用于更新您网站的缓存版本,而无需手动重新加载页面。

这是来自 HTML5 Rocks 上 Beginner's Guide to Using the Application Cache 的代码示例,解释了如何将用户更新到您网站的最新版本:

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

有关更多信息,另请参阅 Mozilla 开发者网络上的 Using the application cache

2016 年更新

网络上的事情变化很快。 这个问题是在 2009 年提出的,在 2012 年我发布了一个关于处理问题中描述的问题的新方法的更新。又过了 4 年,现在看来它已经被弃用了。感谢 cgaldiolo 在 cmets 中指出这一点。

目前,截至 2016 年 7 月,HTML Standard, Section 7.9, Offline Web applications 包含弃用警告:

此功能正在从 Web 平台中删除。 (这是一个需要很多年的漫长过程。)使用任何 此时非常不鼓励使用离线 Web 应用程序功能。 请改用服务人员。

我在 2012 年引用的 Mozilla 开发者网络上的 Using the application cache 也是如此:

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

另见Bug 1204581 - Add a deprecation notice for AppCache if service worker fetch interception is enabled

【讨论】:

  • 这是否意味着您需要使用和维护缓存清单文件?
  • 警告:应用缓存(AppCache)接口已被弃用
  • 那么,截至 2017 年的当前建议是什么?
  • 2017:使用 Service Worker。
  • 2021 年有什么建议吗?
【解决方案4】:

并非如此。一种方法是在交付内容时发送适当的标头以强制浏览器重新加载:

Making sure a web page is not cached, across all browsers.

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

另一种不太干净但有时只有在您无法控制服务器端的标头时才有的方法是向正在调用的资源添加随机 GET 参数:

myimage.gif?random=1923849839

【讨论】:

  • 正确版本文件真的更好。这是对带宽的极大浪费,而且可能更重要的是,会大大降低您的网站速度。
  • 这真的取决于情况,不是吗?如果您正在编写 CMS 并需要确保正确更新所有更改的资源,则有时无法绕过这两个选项之一。
  • 这样的解决方案应该被否决。我们有责任尽可能降低互联网的二氧化碳排放量。
  • 正如@derobert 所说,这完全是浪费带宽,也会减慢页面加载速度,因为在每次刷新时,您都会强制客户端再次加载资源,即使它没有更改,更好的方法是散列文件并将其作为查询参数发送,因此它只会在文件更改时更改。
【解决方案5】:

对于静态资源,正确的缓存是使用查询参数和每个部署或文件版本的值。这将在每次部署后清除缓存。

/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" />

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

【讨论】:

  • 感谢您的回答,但是当我们在 BundleTable 中添加资源时该怎么做?
  • 在我的情况下,这是返回“0.0.0.0”作为版本。要获取 MVC 应用程序的 dll 版本,请改用:?version=@ViewContext.Controller.GetType().Assembly.GetName().Version
  • 我发现这会阻止 Firefox 和 Chrome 完全缓存内容。
【解决方案6】:

我遇到了类似的问题,我就是这样解决的:

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

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

    <script type="text/javascript" src="update_cache.js"></script>
    
  3. &lt;body&gt; 部分我插入了 onload 函数:

    <body onload="checkForUpdate()">
    
  4. cache.manifest 中,我已将所有要缓存的文件放入其中。现在很重要的是,它在我的案例(Apache)中只需每次更新“版本”注释即可。也可以选择在名称末尾使用“?ver=001”或其他名称命名文件,但它不需要。仅更改 # version 1.01 会触发缓存更新事件。

    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
    

    发生是因为每个“子”文件都试图在页面已经缓存时缓存页面。

  5. 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 页面会更新缓存。

解决方案的部分不是我的,但我通过互联网找到了它们并将它们放在一起以便它工作。

【讨论】:

  • 我能知道 CACHE.MANIFEST 写在哪里吗?
  • Shweta Gulati 清单文件应与“索引”文件位于同一文件夹中。什么时候它不起作用?
  • @ShwetaGulati 是的,缓存不会检测到 html 文件中的更改 - 这就是您必须更新清单文件中的版本号的原因,因为它是正在检查更改的版本号。真的很难帮你,因为我不知道细节。请告诉我您是否已将所有需要缓存的文件放在清单中?路径应该是相对于清单文件的。你可以给我你网站的地址,我可以告诉你是怎么回事:)
  • @ShwetaGulati 这是因为浏览器会自动缓存一些文件以加快页面加载速度。这是默认行为,仅取决于浏览器,因此您不能以任何方式设置它。尤其是 js 文件在浏览器的范围内,因为它们通常在网站的所有页面上使用,所以缓存它们是明智的。除了在清单文件中写入所有文件名来缓存所有文件之外,别无他法。如果你找到了,请告诉我,因为我也需要它:)
  • 文件的绝对路径无关紧要。地址的相对路径很重要,因为浏览器会发送文件请求。 F.ex:我有域 example.com,它在 serwer names.com 上。我的空间是example.names.com。所以我将我的 example.com 域加入到我的服务器空间 example.names.com 作为重定向。为此,我需要将文件夹设置为此重定向的目标。因此,如果我想在 example.names.com 上拥有多个站点,我会创建文件夹“name1”,设置重定向并将所有文件放入其中。路径从这里开始计算。如果我在清单文件中有 name1\scripts\test.js 我写 scripts\test.js.
【解决方案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")?>"

【讨论】:

  • 这一点都不优雅,它会让网站每次都重新加载图像,浪费大量时间下载资源,更好的解决方案是使用filesize而不是随机数,这个将使缓存仅在文件实际更改时重新验证
  • 或图像字节的哈希
  • 这一切都取决于用户的要求。对于大量照片,场景将不同于几张照片。检查文件大小会节省带宽,但也会增加额外的处理,可能会减慢页面加载速度。在我的情况下,图片变化非常频繁,用户获取最新图片是关键的业务决策,这是一个完美的解决方案。
  • 您甚至可以在配置中将其设为静态值,这绝不是理想的方法。
  • " 会更有用!
【解决方案8】:

很多答案都没有抓住重点——大多数开发人员都清楚关闭缓存是低效的。但是,在许多常见情况下效率并不重要,默认缓存行为被严重破坏。

这些包括嵌套的迭代脚本测试(最重要的!)和损坏的第三方软件变通办法。此处给出的解决方案均不足以解决此类常见情况。大多数网络浏览器的缓存过于激进,并且没有提供任何明智的方法来避免这些问题。

【讨论】:

    【解决方案9】:

    将 URL 更新为以下内容对我有用:

    /custom.js?id=1

    通过在?id= 之后添加一个唯一的数字并将其递增以进行新的更改,用户不必按CTRL + F5 来刷新缓存。或者,您可以在 ?id= 之后附加当前时间或 Epoch 的哈希或字符串版本

    类似?id=1520606295

    【讨论】:

      【解决方案10】:

      【讨论】:

        【解决方案11】:

        Here 是关于在 ASP.NET 中设置缓存的 MDSN 页面。

        Response.Cache.SetExpires(DateTime.Now.AddSeconds(60))
        Response.Cache.SetCacheability(HttpCacheability.Public)
        Response.Cache.SetValidUntilExpires(False)
        Response.Cache.VaryByParams("Category") = True
        
        If Response.Cache.VaryByParams("Category") Then
           '...
        End If
        

        【讨论】:

          【解决方案12】:

          不确定这是否真的对您有所帮助,但这就是缓存在任何浏览器上的工作方式。当浏览器请求一个文件时,它应该总是向服务器发送一个请求,除非有“离线”模式。服务器将读取一些参数,如修改日期或 etags。

          服务器将返回未修改的 304 错误响应,并且浏览器将不得不使用其缓存。如果 etag 在服务器端无效或修改日期低于当前修改日期,则服务器应返回带有新修改日期或 etag 或两者的新内容。

          如果没有缓存数据发送到浏览器,我猜行为是不确定的,浏览器可能缓存也可能不缓存不告诉它们如何缓存的文件。如果您在响应中设置缓存参数,它将正确缓存您的文件,然后服务器可能会选择返回 304 错误或新内容。

          这是应该的。在 url 中使用随机参数或版本号更像是一种 hack。

          http://www.checkupdown.com/status/E304.html http://en.wikipedia.org/wiki/HTTP_ETag http://www.xpertdeveloper.com/2011/03/last-modified-header-vs-expire-header-vs-etag/

          看完后我看到还有一个过期日期。如果您有问题,可能是您设置了过期日期。换句话说,当浏览器缓存您的文件时,由于它有一个到期日期,它不应该在该日期之前再次请求它。换句话说,它永远不会向服务器询问文件,也永远不会收到未修改的 304。它只会使用缓存,直到到期日期或缓存被清除。

          所以这是我的猜测,您有某种到期日期,您应该使用最后修改的 etag 或混合使用,并确保没有到期日期。

          如果人们经常刷新文件并且文件没有发生太多更改,那么设置一个大的到期日期可能是明智的。

          我的 2 美分!

          【讨论】:

            【解决方案13】:

            我实现了这个适用于我的简单解决方案(尚未用于生产环境):

            function verificarNovaVersio() {
                var sVersio = localStorage['gcf_versio'+ location.pathname] || 'v00.0.0000';
                $.ajax({
                    url: "./versio.txt"
                    , dataType: 'text'
                    , cache: false
                    , contentType: false
                    , processData: false
                    , type: 'post'
                 }).done(function(sVersioFitxer) {
                    console.log('Versió App: '+ sVersioFitxer +', Versió Caché: '+ sVersio);
                    if (sVersio < (sVersioFitxer || 'v00.0.0000')) {
                        localStorage['gcf_versio'+ location.pathname] = sVersioFitxer;
                        location.reload(true);
                    }
                });
            }
            

            我有一个小文件位于 html 所在的位置:

            “版本.txt”:

            v00.5.0014
            

            这个函数在我所有的页面中都会被调用,所以在加载的时候会检查localStorage的版本值是否低于当前版本并做一个

            location.reload(true);
            

            ...强制从服务器而不是从缓存重新加载。

            (显然,您可以使用 cookie 或其他持久客户端存储来代替 localStorage)

            我选择了这种简单的解决方案,因为只维护一个文件“versio.txt”会强制重新加载整个网站。

            queryString方法很难实现,也是缓存的(如果从v1.1改到之前的版本会从缓存中加载,那么就意味着缓存没有被刷新,所有之前的版本都在缓存中)。

            我是一个小新手,非常感谢您的专业检查和审查,以确保我的方法是一个好的方法。

            希望对你有帮助。

            【讨论】:

              【解决方案14】:

              除了设置 Cache-control: no-cache 之外,如果你希望每次都刷新本地副本,你还应该将 Expires 头设置为 -1(某些版本的 IE 似乎需要这样做)。

              HTTP Cache - check with the server, always sending If-Modified-Since

              【讨论】:

                【解决方案15】:

                有一个技巧可以使用。技巧是在脚本标记中的文件名中附加一个参数/字符串,并在文件更改时更改它。

                &lt;script src="myfile.js?version=1.0.0"&gt;&lt;/script&gt;

                浏览器将整个字符串解释为文件路径,即使“?”后面是什么。是参数。所以现在发生的事情是,下次更新文件时,只需更改网站上脚本标记中的数字(例如 &lt;script src="myfile.js?version=1.0.1"&gt;&lt;/script&gt;),每个用户的浏览器都会看到文件已更改并获取一个新副本。

                【讨论】:

                  【解决方案16】:

                  强制浏览器清除缓存或重新加载正确的数据?我已经尝试了stackoverflow中描述的大多数解决方案,有些工作,但过了一会儿,它最终会缓存并显示之前加载的脚本或文件。是否有另一种方法可以清除缓存(css、js 等)并在所有浏览器上实际运行?

                  到目前为止,我发现如果您更改服务器上文件的日期和时间,可以单独重新加载特定资源。 “清除缓存”并不像应有的那么容易。我没有清除浏览器上的缓存,而是意识到“触摸”缓存的服务器文件实际上会更改服务器上缓存的源文件的日期和时间(在 Edge、Chrome 和 Firefox 上测试),并且大多数浏览器会自动下载最您服务器上最新内容的最新副本(代码、图形以及任何多媒体)。我建议您在程序运行之前复制服务器上最新的脚本和“做触摸的事情”解决方案,这样它就会将所有问题文件的日期更改为最新的日期和时间,然后它将新副本下载到您的浏览器:

                  <?php
                     touch('/www/sample/file1.css');
                     touch('/www/sample/file2.js');
                  ?>
                  

                  然后......你的程序的其余部分......

                  我花了一些时间来解决这个问题(因为许多浏览器对不同命令的行为不同,但它们都会检查文件的时间并与您在浏览器中下载的副本进行比较,如果日期和时间不同,则会进行刷新) , 如果你不能走所谓的正确方法,总有另一种可用和更好的解决方案。最好的问候和快乐的露营。顺便说一下 touch();或替代方案适用于许多编程语言,包括 javascript bash sh php,您可以在 html 中包含或调用它们。

                  【讨论】:

                  • 如果文件被修改,时间戳已经改变,所以再次强制它没有任何好处。
                  • touch 命令根本不会改变文件。它更改日期和时间的属性,将其转换为新版本,欺骗浏览器将其作为新副本下载。
                  【解决方案17】:

                  对于 webpack 用户:-

                  我在我的 webpack 配置中添加了 chunkhash 的时间。这解决了我在每次部署时使缓存失效的问题。我们还需要注意 index.html/asset.manifest 没有缓存在您的 CDN 或浏览器中。 webpack 配置中的块名称配置如下所示:-

                  文件名:[chunkhash]-${Date.now()}.js

                  或者如果你使用的是 contenthash,那么

                  文件名:[contenthash]-${Date.now()}.js

                  【讨论】:

                  • 请格式化您的答案,以获得更好的可视化效果。我们使用降价。您可以编辑您的答案。
                  【解决方案18】:

                  您要清除缓存,还是只是确保当前(更改?)页面没有被缓存?

                  如果是后者,应该就这么简单

                  <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
                  

                  【讨论】:

                  • 我最近在一篇 Chrome 帖子中了解到这种方法,但我只在少数实时服务器、本地主机和 Windows 文件共享上发现了一致的结果......使用 Firefox 3.6。
                  【解决方案19】:

                  如果您是 Wordpress 开发人员,我有一些好消息要告诉您。

                  只需搜索、安装并激活名为:reBusted 的 Wordpress 插件。

                  无需配置。

                  如果内容已更新,它将自动强制刷新缓存,并且它完全可靠地解决了这个问题。已在数百个客户端 Wordpress 网站上测试和使用——在任何地方都能完美运行。

                  怎么推荐都不够。

                  如果您使用 Wordpress,这是迄今为止解决此问题的最佳选择和最优雅的解决方案。

                  享受吧!

                  【讨论】:

                    猜你喜欢
                    • 2016-10-01
                    • 2015-10-29
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-09-01
                    相关资源
                    最近更新 更多