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

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

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


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

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

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

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


当前回答

对于开发:使用浏览器设置:例如,Chrome网络选项卡有一个禁用缓存选项。

对于生产:使用服务器端呈现框架或纯JavaScript代码将唯一的查询参数附加到请求(例如,q?Date.now())。

// Pure JavaScript unique query parameter generation
//
//=== myfile.js

function hello() { console.log('hello') };

//=== end of file

<script type="text/javascript">
    document.write('<script type="text/javascript" src="myfile.js?q=' + Date.now() + '">
    // document.write is considered bad practice!
    // We can't use hello() yet
</script>')

<script type="text/javascript">
    hello();
</script>

其他回答

我这样做的方法是简单地有链接元素到服务器端包含:

<!--#include virtual="/includes/css-element.txt"-->

css-element.txt的内容在哪里

<link rel="stylesheet" href="mycss.css"/>

如果你想链接到my-new-css。css,你只需要改变include。

这个解决方案是用PHP编写的,但是应该很容易适应其他语言。

原始的.htaccess正则表达式可能会导致json-1.3.js等文件出现问题。解决方案是只有在结尾恰好有10位数字时才重写。(因为10位数字涵盖了从2001年9月9日到2286年11月20日的所有时间戳。)

首先,我们在.htaccess中使用下面的重写规则:

RewriteEngine on
RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

现在,我们编写以下PHP函数:

/**
 *  Given a file, i.e. /css/base.css, replaces it with a string containing the
 *  file's mtime, i.e. /css/base.1221534296.css.
 *
 *  @param $file  The file to be loaded.  Must be an absolute path (i.e.
 *                starting with slash).
 */
function auto_version($file)
{
  if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
    return $file;

  $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
  return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}

现在,无论你在哪里包含你的CSS,从下面更改它:

<link rel="stylesheet" href="/css/base.css" type="text/css" />

:

<link rel="stylesheet" href="<?php echo auto_version('/css/base.css'); ?>" type="text/css" />

这样,您就不必再次修改链接标签,用户将始终看到最新的CSS。浏览器将能够缓存CSS文件,但当您对CSS进行任何更改时,浏览器将看到这是一个新的URL,因此它不会使用缓存的副本。

这也适用于图像、favicons和JavaScript。基本上任何不是动态生成的东西。

另一个关于ASP的建议。网的网站,

Set different cache-control:max-age values, for different static files. For CSS and JavaScript files, the chances of modifying these files on server is high, so set a minimal cache-control:max-age value of 1 or 2 minutes or something that meets your need. For images, set a far date as the cache-control:max-age value, say 360 days. By doing so, when we make the first request, all static contents are downloaded to client machine with a 200-OK response. On subsequent requests and after two minutes, we see 304-Not Modified requests on CSS and JavaScript files which avoids us from CSS and JavaScript versioning. Image files will not be requested as they will be used from cached memory till the cache expires. By using the below web.config configurations, we can achieve the above described behavior, <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <staticContent> <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="00.00:01:00"/> </staticContent> <httpProtocol> <customHeaders> <add name="ETAG" value=""/> </customHeaders> </httpProtocol> </system.webServer> <location path="Images"> <system.webServer> <staticContent> <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="180.00:00:00" /> </staticContent> </system.webServer> </location>

如果您不想让客户端缓存文件,这个解决方案似乎是最快实现的。如果你在footer.php中加载文件,用time()调整部分:

<script src="<?php echo get_template_directory_uri(); ?>/js/main.js?v=<?= time() ?>"></script>

你可以把?foo=1234放在CSS / JavaScript导入的末尾,把1234改成你喜欢的任何值。看一下Stack Overflow HTML源代码的例子。

这里的意思是?无论如何,参数都会在请求中被丢弃/忽略,您可以在推出新版本时更改这个数字。


注意:关于这究竟如何影响缓存存在一些争论。我认为它的一般要点是GET请求,无论是否带参数都应该是可缓存的,因此上面的解决方案应该是有效的。

然而,这取决于web服务器和用户使用的浏览器,因为它可以直接要求一个新的版本。