我有一个网站。我想更新我的CSS文件。 20分钟后,上传20次,每个浏览器仍然会拉出相同的CSS文件。我从服务器上删除了该文件。字面上没有CSS文件。我清除了所有浏览器的缓存和历史记录;一切。我加载网站。它仍然拉动旧的CSS文件。观察:
这显然是一个浏览器问题:当我从移动设备加载时,新文件就在那里。那么我怎样才能给我的浏览器提供一个提示,并实际上让它们清晰的cookie /缓存等?
现在我转到另一台从未访问过该网站的计算机,它会提取旧 CSS文件。
请向我解释如何以及为什么这样做。是我的主持人吗?我正在使用Netfirms,但更新CSS文件可能需要多长时间?
答案 0 :(得分:1)
我认为这是“无意识的”服务器端缓存的典型案例。这表明服务器会保留文件的副本以缩短客户端的加载时间。
取决于缓存解决方案,您可以使用.htaccess转换缓存。
希望这有帮助!
答案 1 :(得分:1)
浏览器缓存内容是完全正常的,除非您完全控制希望页面及其资源被缓存的时间。
在这些情况下你想要做的是实现一种叫做“缓存破坏”的东西。缓存破坏的作用是强制浏览器将服务器上已更改的文件视为新请求,只需让浏览器认为它是一个不同的文件或请求即可。
最简单的方法是将类似?v=123
的查询字符串附加到资源(JavaScript,CSS)URL。但是如果使用查询字符串,请注意某些代理将忽略刷新其缓存内容。因此,我处理缓存清除的首选方法是使用重写规则将文件(如style-1391836063.css
)的请求指向服务器上始终具有相同名称的文件,即style.css
。重写规则可以像
RewriteRule (.+)-(\d+).(css|js)$ $1.$3 [L]
整个魔法在1391836063
部分,实际上是filemtime()生成的时间戳。该时间戳表示文件最后一次更改,因此只要style.css
保持不变,它就会保留相同的值。在这种情况下,浏览器只会看到相同的资源名称,并且无需重新下载,因为它已经缓存并被认为是最新的。
但是,如果style.css
确实发生了变化,那么修改后的时间戳也会改变,这将导致不同的数字部分,即style-1391867247.css
。如果发生这种情况,浏览器将被迫丢弃任何缓存数据,并将该请求视为一种全新的资源。
但是,为了实现这一点,您还需要服务器端支持,或者换句话说,需要执行所有指纹识别的脚本(指纹识别实际上是引用此技术的正确方法)。无论您使用何种服务器端技术,该过程都将如下所示。
filemtime()
读取其修改后的时间戳。然后将其附加到实际资源名称(style.css
变为类似style-1391867247.css
)这是我写的一个PHP类,用于对我的大多数项目执行fingeprinting。请注意,为避免不必要的处理,此类应与某种形式的服务器端缓存一起使用,以避免在不需要时进行fingeprinting。此外,代码引用了一些外部常量和类,应该忽略它们,因为代码只是试图演示一种如何完成指纹识别的方法。
/**
* CacheBusting class responsible for fingerprinting CSS and JavaScript resources in order to prevent caching issues.
*/
class CacheBuster {
/**
* Parses the loaded (X)HTML code and fingerprints all resources with their Last Modified timestamp.
*
* @param string $content XHTML content to fingerprint.
* @return mixed Either fingerprinted $content on success or false on failure.
*/
public static function fingerprint($content){
/**
* ExtendedDOMDocument for manipulating content data (something written by me to replace the gimpy DOMDocument class)
*
* @var ExtendedDOMDocument
*/
$dom;
/**
* XPath responsible for handling $dom.
*
* @var DOMXPath
*/
$xpath;
/**
* List of extracted DOM nodes.
*
* @var DOMNodeList
*/
$nodes;
/**
* Helper variable containing current resource URI.
*
* @var string
*/
$resource = '';
/**
* Helper variable containing all the results from regex matches.
*
* @var array
*/
$matches = array();
/**
* Array of resource URIs with their corresponding fingerprint versions.
*
* @var array
*/
$fingerprints = array();
// In case to $content is pnot provided false is returned.
if(!strlen($content)){
return false;
}
// Loading $content into DOMDocument parser.
$dom = new ExtendedDOMDocument();
$dom->loadHTML($content);
// Extracting <script> and <link> nodes.
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//script|//link');
// Traversing the extracted nodes in order to find out the exact names of the CSS and JavaScript resources and then create the appropriate fingerprint.
foreach($nodes as $node){
//Only local resources with specified "src" or "href"" are taken into account.
switch($node->getAttribute('type')){
case 'text/javascript' :
$resource = $node->getAttribute('src');
break;
case 'text/css' :
$resource = $node->getAttribute('href');
break;
default:
// In case no type is specified we probe for either "src" or "href" but if nothing is found we skip this node.
/**
* Value of the 'src' attribute for the current node, if any.
*
* @var string
*/
$src = $node->getAttribute('src');
/**
* Value of the 'href' attribute for the current node, if any.
*
* @var string
*/
$href = $node->getAttribute('href');
if(strlen($src) && strpos($src, '.js')){
$resource = $src;
} else if(strlen($href) && strpos($href, '.css')) {
$resource = $href;
} else {
//No luck? Skipping the current node.
continue;
}
}
// Generating fingerprint pairs.
if(!strlen(trim($resource)) || (stripos($resource, 'http://') !== false) || (stripos($resource, 'https://') !== false)){
// Skipping inline and remote scripts.
continue;
} else {
// Fingerprinting resources...
preg_match('/(.+)\.(css|js)/', $resource, $matches);
if(file_exists(APP_FOLDER . $matches[0])){ // Resource exists.
$fingerprints[] = array(
'original' => $resource,
'fingerprinted' => $matches[1] . '-' . filemtime(APP_FOLDER . $matches[0]) . '.' . $matches[2]
);
}
}
}
// Time to make fingerprint pair replacements.
foreach($fingerprints as $pair){
$content = str_replace($pair['original'], $pair['fingerprinted'], $content);
}
return $content;
}
}
您可以像使用代码中的任何位置一样简单地使用该类。
$output = CacheBuster::fingerprint($MARKUP);