我们希望在生产发布时进行缓存清除,但不想一开始就浪费很多时间来制定这样的系统。我的想法是在CSS和JS文件的末尾应用一个带有当前版本号的参数:
<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>
两个问题:这样做会有效地破坏缓存吗?param参数会导致浏览器从该URL永远不会缓存响应,因为param参数指示这是动态内容吗?
我们希望在生产发布时进行缓存清除,但不想一开始就浪费很多时间来制定这样的系统。我的想法是在CSS和JS文件的末尾应用一个带有当前版本号的参数:
<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>
两个问题:这样做会有效地破坏缓存吗?param参数会导致浏览器从该URL永远不会缓存响应,因为param参数指示这是动态内容吗?
参数?v=1.123
表示一个查询字符串,因此浏览器会认为它是来自于新的路径,比如说?v=1.0
。这将导致它从文件中加载,而不是从缓存中加载。根据您的需求。
此外,浏览器将假定下一次调用?v=1.123
时源代码将保持不变,并且应该将其与该字符串一起缓存。因此,无论你的服务器设置如何,它都将保留在缓存中,直到你转移到?v=1.124
或者更高版本。
/static/v22/file.css
,因为您可以通过单个文件夹重命名来处理多个文件,例如/static/v23/file.css
和/static/v23/mystuff.js
。 - Brad Parks把版本号放在实际的文件名中更安全。这样可以同时存在多个版本,因此您可以发布新版本,如果任何缓存的HTML页面仍然要求旧版本,则它们将获取与其HTML兼容的版本。
请注意,在互联网上最大的版本化部署之一中,jQuery在实际的文件名中使用版本号,它可以安全地允许多个版本共存,而不需要任何特殊的服务器端逻辑(每个版本只是不同的文件)。
这使得在部署新页面和新链接文件时缓存失效一次(这正是您想要的),从那时起,这些版本可以被有效地缓存(这也是您想要的)。
正如其他人所说,使用查询参数进行缓存破坏通常被认为是一个不好的做法,并且已经有很长时间了。更好的方法是在文件名中反映版本号。Html5 Boilerplate 建议避免使用查询字符串等方式。
尽管如此,在我看过的所有引用来源的建议中,似乎都从Steve Souders 2008年的文章中汲取智慧。他的结论基于当时代理服务器的行为,现在可能或可能不再相关。然而,在没有更多当前信息的情况下,更改文件名是安全的选择。
一旦客户端下载了资源,它将进行一次缓存破坏,除非:
一般来说,这应该是没有问题的,但如果有一个中间缓存(代理)被配置为忽略请求参数,则可能无法正常工作。
例如,如果您通过Akamai CDN提供静态内容,则可以配置它忽略请求参数以防止使用此方法进行缓存破坏。
在这里发现了两种技术(查询字符串与文件名)的比较:
作为查询字符串的版本有两个问题。
首先,可能不是所有实现缓存的浏览器都需要我们破坏查询字符串。据说某些代理(可能是旧的)会忽略与其缓存行为相关的查询字符串。
其次,在某些更复杂的部署方案中,您将拥有多个前端和/或多个后端服务器,而升级则绝非瞬间完成。您需要能够同时提供资产的旧版本和新版本。例如,查看在使用Google App Engine时如何影响您。
这在很大程度上取决于您希望缓存的强度如何。例如,Squid代理服务器(可能还有其他服务器)默认不会对带查询字符串的URL进行缓存-至少在写这篇文章时是这样的。如果您不介意某些使用情况导致不必要的缓存未命中,则可以使用查询参数。但是,非常容易设置基于文件名的缓存破坏方案来避免此问题。
1.2.3/css/styles.css
和css/styles.css
提供相同的文件,因为htaccess文件会去除并忽略第一个目录。<?php
$version = "1.2.3";
?>
<html>
<head>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<link rel="stylesheet" type="text/css" href="<?php echo $version ?>/css/styles.css">
</head>
<body>
<script src="<?php echo $version ?>/js/main.js"></script>
</body>
</html>
RewriteEngine On
# if you're requesting a file that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-f
# likewise if a directory that exists, do nothing
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise, rewrite foo/bar/baz to bar/baz - ignore the first directory
RewriteRule ^[^/]+/(.+)$ $1 [L]
<script type="text/javascript">
// front end cache bust
var cacheBust = ['js/StrUtil.js', 'js/protos.common.js', 'js/conf.js', 'bootstrap_ECP/js/init.js'];
for (i=0; i < cacheBust.length; i++){
var el = document.createElement('script');
el.src = cacheBust[i]+"?v=" + Math.random();
document.getElementsByTagName('head')[0].appendChild(el);
}
</script>
<link rel="stylesheet" href="style.css?v=1487935578" />
。 - oelna