网站如何调用不再存在的文件?

时间:2014-02-09 18:17:47

标签: html css

我有一个网站。我想更新我的CSS文件。 20分钟后,上传20次,每个浏览器仍然会拉出相同的CSS文件。我从服务器上删除了该文件。字面上没有CSS文件。我清除了所有浏览器的缓存和历史记录;一切。我加载网站。它仍然拉动旧的CSS文件。观察:

  1. 这显然是一个浏览器问题:当我从移动设备加载时,新文件就在那里。那么我怎样才能给我的浏览器提供一个提示,并实际上让它们清晰的cookie /缓存等?

  2. 现在我转到另一台从未访问过该网站的计算机,它会提取 CSS文件。

  3. 请向我解释如何以及为什么这样做。是我的主持人吗?我正在使用Netfirms,但更新CSS文件可能需要多长时间?

2 个答案:

答案 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。如果发生这种情况,浏览器将被迫丢弃任何缓存数据,并将该请求视为一种全新的资源。

但是,为了实现这一点,您还需要服务器端支持,或者换句话说,需要执行所有指纹识别的脚本(指纹识别实际上是引用此技术的正确方法)。无论您使用何种服务器端技术,该过程都将如下所示。

  1. 使用DOM解析器,您可以查找对CSS和/或JavaScript文件的所有引用。
  2. 对于您找到的每个引用,您检查服务器上是否存在该文件,如果存在,则使用filemtime()读取其修改后的时间戳。然后将其附加到实际资源名称(style.css变为类似style-1391867247.css
  3. 您将指纹代码返回浏览器。
  4. 这是我写的一个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);