使用CakePHP(和资产压缩)处理图像缓存

时间:2013-07-06 04:10:42

标签: cakephp caching

来自Yahoo!的Best Practices for Speeding Up Your Web Site文档:

  

过期标题最常用于图像,但它们应该是   用于所有组件,包括脚本,样式表和Flash   组件。

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

这是来自同一个Yahoo!的另一个引用!文件:

  

请记住,如果您使用远期的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. 它使用查询字符串not recommended
  2. 每次访问特定视图时都会检查图像的时间戳。是的,您可以缓存视图,但是您可能希望在视图的缓存版本到期之前更新该视图中的图像,因此您必须执行任何操作才能触发该视图以进行重新缓存,我不认为是优雅的。
  3. 至于处理CSS background-image的缓存清除,我必须手动更新LESS文件。绝对不优雅。

    如何使用CakePHP和/或Asset Compress处理图像缓存?

1 个答案:

答案 0 :(得分:3)

缓存失效,性能和网络

人们普遍认为编程中最困难的事情之一是cache invalidation。但是,对于不是真正的资产(js文件,css文件,图像等),服务网络资产的最佳逻辑是:

然而,当应用于网络时会出现一个复杂情况。

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

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

这显然会在加载css文件时触发/img/bar.gif请求。假设图像是使用适当的标头提供的,只有两种方法可以加载bar.gif的更新版本:

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

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

版本前缀资产网址 - &gt;永远不会有问题

解决css / js / files问题的一种简单方法是使您的构建号成为URL的一部分:

/v123/css/foo.css
 ^

您可以通过修改app helper 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文件的请求是特定于应用程序版本的,但引用的图像不是,并且即使使用新的应用程序版本,也会从浏览器缓存中读取(如果相关)。

实现相同的结果,不对文件系统进行任何更改

如果您不想更改文件夹结构,可以使用重写规则similar to the one in h5bp's进行文件名缓存清除:

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

这意味着网址/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,fonts和js请求进行版本前缀;间接对css-images执行相同的操作(假设他们使用background-image:url('img/bar.gif');形式的相对URL)而不将相同的逻辑应用于其他资产(用户头像,他们上传的猫视频,等等)。

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

这是谷歌所做的=)。

在一天结束时,它可以选择您希望构建过程的复杂程度,以及真正的好处。许多用户have empty browser caches,因此对于随机用户来说,应用程序的缓存逻辑很可能只适用于他们当前的访问 - 一次性使整个资产缓存到期的主要原因之一就是坏事。