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

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

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


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

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

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

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


当前回答

不要使用foo.css?version=1!

浏览器不应该缓存带有GET变量的url。据http://www.thinkvitamin.com/features/webapps/serving-javascript-fast网站报道,尽管ie和Firefox会忽略这一点,但Opera和Safari不会!相反,使用foo.v1234.css,并使用重写规则去除版本号。

其他回答

最简单的方法是利用PHP文件读取功能。只需让PHP将文件内容回显到标记中。

<?php
//Replace the 'style.css' with the link to the stylesheet.
echo "<style type='text/css'>".file_get_contents('style.css')."</style>";
?>

如果您使用的是PHP以外的东西,则根据语言的不同会有一些变化,但几乎所有语言都有打印文件内容的方法。将它放在正确的位置(在部分中),这样就不必依赖浏览器了。

这里的所有答案似乎都表明在命名方案中存在某种版本控制,但这也有其缺点。

浏览器应该通过读取web服务器的响应,特别是HTTP报头来清楚地知道什么该缓存,什么不该缓存——这个资源的有效期是多长?自上次检索该资源以来,该资源是否已更新?等。

如果事情配置“正确”,只是更新你的应用程序的文件应该(在某些时候)刷新浏览器的缓存。例如,你可以配置你的web服务器,告诉浏览器永远不缓存文件(这是一个坏主意)。

更深入的解释在Web缓存的工作原理中。

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

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

?$Now.Format(dmYHis)

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

我在为我的SPA寻找解决方案时遇到了这个问题,它只有一个列出所有必要文件的index.html文件。虽然我得到了一些帮助我的线索,但我找不到一个快速而简单的解决方案。

最后,我编写了一个快速页面(包括所有代码)来自动版本HTML/JavaScript index.html文件,作为发布过程的一部分。它工作完美,只更新新文件根据日期最后修改。

你可以在Autoversion your SPA index.html上看到我的文章。还有一个独立的Windows应用程序。

代码的核心是:

private void ParseIndex(string inFile, string addPath, string outFile)
{
    string path = Path.GetDirectoryName(inFile);
    HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
    document.Load(inFile);

    foreach (HtmlNode link in document.DocumentNode.Descendants("script"))
    {
        if (link.Attributes["src"]!=null)
        {
            resetQueryString(path, addPath, link, "src");
        }
    }

    foreach (HtmlNode link in document.DocumentNode.Descendants("link"))
    {
        if (link.Attributes["href"] != null && link.Attributes["type"] != null)
        {
            if (link.Attributes["type"].Value == "text/css" || link.Attributes["type"].Value == "text/html")
            {
                resetQueryString(path, addPath, link, "href");
            }
        }
    }

    document.Save(outFile);
    MessageBox.Show("Your file has been processed.", "Autoversion complete");
}

private void resetQueryString(string path, string addPath, HtmlNode link, string attrType)
{
    string currFileName = link.Attributes[attrType].Value;

    string uripath = currFileName;
    if (currFileName.Contains('?'))
        uripath = currFileName.Substring(0, currFileName.IndexOf('?'));
    string baseFile = Path.Combine(path, uripath);
    if (!File.Exists(baseFile))
        baseFile = Path.Combine(addPath, uripath);
    if (!File.Exists(baseFile))
        return;
    DateTime lastModified = System.IO.File.GetLastWriteTime(baseFile);
    link.Attributes[attrType].Value = uripath + "?v=" + lastModified.ToString("yyyyMMddhhmm");
}
location.reload(true)

或者使用检查器中的“网络”([CTRL] + [I]),点击“禁用缓存”,点击垃圾图标,点击“加载”/“获取”