5

来自 Yahoo! 的网站加速最佳实践文档:

Expires 标头最常用于图像,但它们应该用于所有组件,包括脚本、样式表和 Flash 组件。

我使用“mod_expires”Apache 模块遵循上述建议。我的实现很像 HTML5 Boilerplate 的。请参阅此 .htaccess 代码

这是来自同一雅虎的另一个报价!文档:

请记住,如果您使用未来的 Expires 标头,则必须在组件更改时更改组件的文件名。在雅虎!我们经常将此步骤作为构建过程的一部分:版本号嵌入在组件的文件名中,例如 yahoo_2.0.6.js。

我使用 Mark Story 的Asset Compress插件处理了我的 CSS 和 JavaScript 文件。只需将 Asset Compress 的 shell 作为构建过程的一部分。

现在对于我遇到的两个问题,都与图像有关:

我的整个网站都有常规<img>标签,我也有 CSS background-image。我目前没有一种优雅的方式来处理这两种图像中的任何一种的缓存破坏。对于<img>标签,我的“core.php”文件中有这一行:

Configure::write('Asset.timestamp', 'force');

尽管这确实提供了一种自动处理标签缓存破坏的方法<img>(假设标签是使用 生成的$this->Html->image(...)),但我认为这并不优雅,原因有两个:

  1. 它使用查询字符串,不推荐
  2. 每次访问特定视图时都会检查图像的时间戳。是的,您可以缓存视图,但您可能希望在视图的缓存版本过期之前更新该视图中的图像,因此您必须执行触发该视图重新缓存所需的任何操作,我认为这不优雅。

至于处理 CSSbackground-image的缓存破坏,我必须手动更新 LESS 文件。绝对不优雅。

CakePHP 和/或 Asset Compress 应该如何处理图像缓存?

4

1 回答 1

3

缓存失效、性能和网络

人们普遍认为,编程中最难做的事情之一就是缓存失效。然而,对于资产(js 文件、css 文件、图像等)来说,提供 Web 资产并不是真正的最佳逻辑:

然而,当应用于网络时,有一个复杂的问题。

考虑对 的请求/css/main.css,其中包含:

body {
    background-image:url('../img/bar.gif');
}

显然,这将触发对/img/bar.gif何时加载 css 文件的请求。假设图像带有适当的标头,则只有两种方法可以加载 的更新版本bar.gif

  • 更改css文件的内容
  • 更改css文件所在的文件夹

第一个是有问题的,如果它不是自动化的(即使是自动化的,也可能出错),第二个很容易。

版本前缀资产 url -> 再也不会有问题

解决 css/js/files 问题的一种简单方法是使您的内部版本号成为 url 的一部分:

/v123/css/foo.css
 ^

您可以通过修改您的应用程序助手 webroot 功能来做到这一点,例如:

public function webroot($file) {
    $file = parent::webroot($file);
    if (Configure::read('debug')) {
        return $file;
    }

    return '/' . Configure::read('App.version') . $file;
}

顺便说一句,使用 cdn 是相同的技术——这可能是提高前端性能所能做的最好的事情。

通过这种方式,当您提升您的网站版本时 - 所有资产都会获得新的网址。请注意,使用此技术,所有引用的资产都需要使用相对 url,而不是绝对:

.foo {
    /* background-image:url('/img/bar.gif'); // won't work */
    background-image:url('../img/bar.gif');
}

否则,对 css 文件的请求是特定于应用程序版本的,但引用的图像不是,即使使用新的应用程序版本,也会从浏览器缓存(如果相关)中读取。

实现相同的结果,不更改文件系统

如果您不想更改文件夹结构,可以使用类似于 h5bp 中的重写规则进行文件名缓存清除:

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^/v\d+/(css|files|js)/(.+)$ /$1/$2 [L]
</IfModule>

这将意味着 url在请求时/v123/css/main.css提供内容。/css/main.css

解析css文件很复杂

你在评论中提到

我认为更改一项资产会导致重新下载所有资产的事实是一个交易破坏者

除非您每分钟都发布一个新的生产版本 - 这不会成为问题(除非您有 GB 的缓存内容,在这种情况下......您有不同的问题)。拥有特定于文件的高性能缓存逻辑的唯一方法是例如将站点中的每个文件存储为文件内容的 sha1 - 应用于 css 文件,这意味着替换../img/foo.gif../img/<hash of foo.gif's contents>.gif.

没有什么可以停止使用多种技术,例如使用以下结构:

app
    webroot
        css
            img <- css assets only
        fonts
        img
        js

您可以为您的 css、字体和 js 请求添加版本前缀;间接地对 css-images 执行相同的操作(假设它们使用表单的相对 url background-image:url('img/bar.gif');),而不将相同的逻辑应用于其他资产(用户头像、他们上传的猫视频等)。

或者对所有图像使用数据 uri

这就是谷歌所做的=)。

归根结底,您需要在构建过程的复杂程度和真正的好处之间做出选择。许多用户的浏览器缓存为空,因此对于随机用户而言,应用程序的缓存逻辑很可能仅适用于他们当前的访问——一次性使整个资产缓存过期的主要原因之一并不是那么糟糕事物。

于 2013-07-06T07:49:31.857 回答