我注意到一些浏览器(特别是Firefox和Opera)非常热衷于使用.css和.js文件的缓存副本,甚至在浏览器会话之间。当您更新其中一个文件时,这会导致一个问题,但用户的浏览器会继续使用缓存的副本。

当文件发生更改时,强迫用户浏览器重新加载文件的最优雅的方法是什么?

理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件。


我发现John Millikin和da5id的建议很有用。这有一个专门的术语:自动版本控制。

我在下面发布了一个新的答案,这是我最初的解决方案和约翰的建议的结合。

SCdF建议的另一个想法是将伪查询字符串附加到文件中。(一些自动使用时间戳作为伪查询字符串的Python代码是由pi..提交的)

然而,关于浏览器是否缓存带有查询字符串的文件还存在一些讨论。(请记住,我们希望浏览器缓存该文件并在以后的访问中使用它。我们只希望它在文件更改时再次获取该文件。)


当前回答

在ASP。NET Core你可以通过添加'asp-追加-版本'来实现:

<link rel="stylesheet" href="~/css/xxx.css" asp-append-version="true" />

 <script src="~/js/xxx.js" asp-append-version="true"></script>

它将生成HTML:

<link rel="stylesheet" href="/css/xxx.css?v=rwgRWCjxemznsx7wgNx5PbMO1EictA4Dd0SjiW0S90g" />

每当您更新文件时,框架将生成一个新的版本号。

其他回答

一个特定于silverstripe的答案是:http://api.silverstripe.org/3.0/source-class-SS_Datetime.html#98-110:

希望这将帮助使用SilverStripe模板的人,并试图在每次页面访问/刷新时强制重新加载缓存图像。在我的情况下,它是一个GIF动画,只播放一次,因此没有重放后,它被缓存。在我的模板中,我简单地添加了:

?$Now.Format(dmYHis)

添加到文件路径的末尾,以创建唯一的时间戳并强制浏览器将其视为新文件。

好吧,我已经通过改变JavaScript文件版本每次页面加载通过添加一个随机数的JavaScript文件版本,如下所示:

// Add it to the top of the page
<?php
    srand();
    $random_number = rand();
?>

然后将随机数应用到JavaScript版本,如下所示:

<script src="file.js?version=<?php echo $random_number;?>"></script>

对于在开发和测试时遇到此问题的开发人员:

简单地删除缓存。

“保持缓存与文件一致”..太麻烦了。

一般来说,我不介意加载更多的文件——甚至在大多数项目中加载没有改变的文件——实际上是无关紧要的。在开发应用程序时,我们主要从磁盘加载,在localhost:port上加载,因此网络流量的增加不是一个棘手的问题。

大多数小项目只是玩玩而已——它们从来没有真正投入生产。所以对他们来说,你不需要更多的东西……

因此,如果你使用Chrome DevTools,你可以遵循如下图所示的禁用缓存方法:

如果你有Firefox缓存问题:

只在开发过程中这样做。你还需要一种机制来强制重新加载用于生产,因为如果你频繁地更新你的应用程序,你的用户将使用旧的缓存失效的模块,而你没有提供一个专门的缓存同步机制,就像上面的答案中描述的那样。

是的,这个信息已经在以前的答案中,但我仍然需要做谷歌搜索才能找到它。

我建议您使用实际CSS文件的MD5散列,而不是手动更改版本。

URL应该是这样的

http://mysite.com/css/[md5_hash_here]/style.css

您仍然可以使用重写规则来去除散列,但优点是现在您可以将缓存策略设置为“永远缓存”,因为如果URL相同,这意味着文件没有改变。

然后,您可以编写一个简单的shell脚本来计算文件的散列并更新标记(您可能希望将其移动到一个单独的文件中进行包含)。

只要在CSS每次更改时运行该脚本就可以了。浏览器只会在文件被修改时重新加载。如果你做了一个编辑,然后撤销它,为了让你的访问者不重新下载,你不需要确定需要返回到哪个版本。

只需使用服务器端代码添加文件的日期…这样,它将被缓存,只有当文件更改时才会重新加载。

在ASP。NET:

<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />

<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>

这可以简化为:

<script src="<%= Page.ResolveClientUrlUnique("~/js/custom.js") %>" type="text/javascript"></script>

通过在项目中添加扩展方法来扩展Page:

public static class Extension_Methods
{
    public static string ResolveClientUrlUnique(this System.Web.UI.Page oPg, string sRelPath)
    {
        string sFilePath = oPg.Server.MapPath(sRelPath);
        string sLastDate = System.IO.File.GetLastWriteTime(sFilePath).ToString();
        string sDateHashed = System.Text.RegularExpressions.Regex.Replace(sLastDate, "[^0-9]", "");

        return oPg.ResolveClientUrl(sRelPath) + "?d=" + sDateHashed;
    }
}