通过参数缓存中断

我们希望在生产部署时缓存胸部,但是不想浪费大量时间去研究一个系统来完成这项工作。我的想法是在 css 和 js 文件的末尾应用一个参数,使用当前版本号:

<link rel="stylesheet" href="base_url.com/file.css?v=1.123"/>

两个问题: 这会有效地破坏缓存吗?参数是否会导致浏览器永远不缓存来自该 URL 的响应,因为参数表明这是动态内容?

121572 次浏览

两个问题: 这会有效地破坏缓存吗?

是的。尽管我记得他们(每天有数以百万计的访问者和数以亿计的不同的客户端和代理版本和配置)有一些反常的边缘情况,即使这样也不足以破坏缓存。但是,一般的假设是,这将工作,并且是在客户机上中断缓存的合适方法。

参数是否会导致浏览器永远不缓存来自该 URL 的响应,因为参数表明这是动态内容?

没有。参数不会更改缓存策略; 服务器发送的缓存头仍然适用,如果不发送任何缓存头,则为浏览器的默认值。

参数 ?v=1.123表示一个查询字符串,因此浏览器将认为它是来自(比如说) ?v=1.0的新路径。因此导致它从文件加载,而不是从缓存加载。如你所愿。

并且,浏览器将假定下次调用 ?v=1.123应该缓存该字符串时,源将保持不变。因此,无论您的服务器如何设置,它都将保持缓存,直到您移动到 ?v=1.124左右。

在客户端下载资源之后,它将一次性终止缓存,其他的响应将从客户端缓存中提供,除非:

  1. V 参数更新。
  2. 客户端清空他们的缓存

将版本号放在实际的文件名中更安全。这允许同时存在多个版本,因此您可以生成一个新版本,如果任何缓存的 HTML 页面仍然存在,请求旧版本,他们将获得与他们的 HTML 工作的版本。

注意,在互联网上最大的版本部署之一,jQuery 在实际文件名中使用版本号,它安全地允许多个版本共存,而不需要任何特殊的服务器端逻辑(每个版本只是一个不同的文件)。

当您部署新的页面和新的链接文件(这是您想要的)时,这会中断缓存一次,从那时起这些版本就可以被有效地缓存(这也是您想要的)。

一般来说,这样应该没问题,但是如果有一个中间缓存(代理)被配置为忽略请求参数,那么这样做就可能不起作用。

例如,如果通过 Akamai CDN 提供静态内容,可以将其配置为忽略请求参数,以防止使用此方法破坏缓存。

这在很大程度上取决于您希望高速缓存的健壮程度。例如,鱿鱼代理服务器(可能还有其他服务器)的 默认为 < em > not 缓存 URL 使用一个查询字符串——至少在撰写这篇文章时是这样的。如果您不介意某些用例导致不必要的缓存丢失,那么继续查询参数。但是 非常很容易建立一个基于文件名的缓存破坏方案,从而避免了这个问题。

正如其他人所说,使用查询参数破坏缓存通常被认为是一个糟糕的主意(tm) ,而且这种情况已经持续了很长时间。最好在文件名中反映版本。使用查询字符串的 Html5样板 建议反对

尽管如此,我所看到的那些引用资料来源的建议,似乎都借鉴了史蒂夫•索德斯(Steve Souders)的 2008年的文章的智慧。他的结论是基于当时代理人的行为得出的,这些结论在当今可能是相关的,也可能是不相关的。尽管如此,在缺乏更多最新信息的情况下,更改文件名是安全的选择。

找到了两种技术的比较(查询字符串与文件名) 给你:

作为查询字符串的版本有两个问题。

首先,它可能并不总是一个实现缓存的浏览器,我们需要通过它进行突破。据说,某些(可能是较老的)代理就其缓存行为而言确实忽略了查询字符串。

其次,在某些更复杂的部署场景中,如果您有多个前端和/或多个后端服务器,升级绝不是即时的。您需要能够同时为您的资产的旧版本和新版本提供服务。例如,当你使用 Google App Engine 时,这会对你产生怎样的影响。

另一种类似的方法是使用 Htaccess 改写在提供文件时忽略部分路径。从未缓存的索引页引用文件的最新路径。

从开发的角度来看,这和使用 params 作为版本号一样简单,但是它和文件名方法一样健壮。

使用路径中被忽略的部分作为版本号,服务器就会忽略它并提供未缓存的文件。

1.2.3/css/styles.csscss/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>

注意,这种方法意味着您需要禁用索引页面的缓存 -使用 < meta > 标记关闭所有浏览器中的缓存?

. htaccess 文件

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]

您可以在任何允许 URL 重写的服务器平台上采用相同的方法

(改编自 Mod _ rewrite-将目录重写为查询字符串,除了/# !/的重写条件)

... 如果您需要为您的索引页面/站点入口点缓存崩溃,您可以始终使用 使用 JavaScript来刷新它。

<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>
 <script>
var storedSrcElements = [
"js/exampleFile.js",
"js/sampleFile.js",
"css/style.css"
];


var head= document.getElementsByTagName('head')[0];
var script;
var link;
var versionNumberNew = 4.6;


for(i=0;i<storedSrcElements.length;i++){
script= document.createElement('script');
script.type= 'text/javascript';
script.src= storedSrcElements[i] + "?" + versionNumberNew;
head.appendChild(script);
}




</script>




### Change the version number  (versionNumberNew) when you want the new files to be loaded  ###

希望这能帮助您注入外部 JS 文件

<script type="text/javascript">
var cachebuster = Math.round(new Date().getTime() / 1000);
document.write('<scr'+'ipt type="text/javascript" src="external.js?cb=' +cachebuster+'"></scr' + 'ipt>');
</script>

资料来源 -JavaScript 中的 Cachebuster 代码