如何强制浏览器重新加载缓存的CSS / JS文件?

空扰寡人 提交于 2019-12-14 18:17:26

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

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

问题是:强迫用户浏览器在文件更改后重新加载文件的最优雅方法是什么?

理想情况下,该解决方案不会强制浏览器在每次访问页面时重新加载文件。 我将发布自己的解决方案作为答案,但是我很好奇是否有人有更好的解决方案,我将让您决定。

更新:

经过一段时间的讨论后,我发现John Millikinda5id的建议很有用。 事实证明有一个术语: 自动版本化

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

SCdF建议的另一个想法是将伪查询字符串附加到文件中。 (一些由pi提交的自动使用时间戳作为伪查询字符串的Python代码。) 但是,关于浏览器是否将使用查询字符串缓存文件存在一些讨论。 (请记住,我们希望浏览器缓存文件并在以后的访问中使用它。我们只希望它在更改后再次获取文件。)

由于尚不清楚假查询字符串会发生什么,因此我不接受该答案。


#1楼

有趣的帖子。 在阅读了所有答案之后,再加上我从未遇到过“伪造”查询字符串的任何问题(我不确定为什么每个人都不太愿意使用它),我猜想解决方案(这消除了对Apache重写规则的需求)就像在接受的答案中一样)是将CSS文件内容的简短哈希值(而不是文件日期时间)计算为伪查询字符串。

这将导致以下结果:

<link rel="stylesheet" href="/css/base.css?[hash-here]" type="text/css" />

当然,在编辑CSS文件的情况下,datetime解决方案也可以完成工作,但是我认为这与css文件的内容有关,与文件datetime无关,那么为什么要混在一起呢?


#2楼

很抱歉带回死线。

@ TomA是正确的。

使用“ querystring”方法不会像下面的Steve Souders所引用的那样被缓存:

...一个流行的代理Squid不会使用查询字符串缓存资源。

@ TomA建议使用style.TIMESTAMP.css,但MD5会好得多,因为只有真正更改内容时,MD5也会更改。


#3楼

更新:重写以合并John Millikinda5id的建议。 该解决方案是用PHP编写的,但应易于适应其他语言。

更新2:结合尼克·约翰逊Nick Johnson)的意见,即原始的.htaccess正则表达式可能会导致json-1.3.js类的文件出现问题。 解决方案是仅在末尾恰好有10位数字时才重写。 (因为10位数字涵盖了从9/9/2001到11/20/2286的所有时间戳。)

首先,我们在.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" />

这样,您无需再次修改link标记,并且用户将始终看到最新的CSS。 浏览器将能够缓存CSS文件,但是当您对CSS进行任何更改时,浏览器会将其视为新的URL,因此它将不使用缓存的副本。

这也可以用于图像,图标和JavaScript。 基本上任何不是动态生成的。


#4楼

您只需将?foo=1234放在css / js导入的末尾,将1234更改为您喜欢的任何值即可。 看看SO html源代码的示例。

有那个想法吗? 无论如何,参数都会被丢弃/忽略,并且在您推出新版本时可以更改该数字。


注意:关于它如何影响缓存,存在一些争论。 我认为一般的主旨是,带有或不带有参数的GET请求都应该是可缓存的,因此上述解决方案应该可以工作。

但是,由Web服务器决定是否要遵守规范的那部分内容以及用户使用的浏览器,这是因为Web服务器可以直接要求任何新版本。


#5楼

我听说这叫做“自动版本控制”。 最常见的方法是将静态文件的mtime包含在URL中的某个位置,然后使用重写处理程序或URL conf将其删除:

也可以看看:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!