代码之家  ›  专栏  ›  技术社区  ›  Dónal

客户端文件缓存

  •  16
  • Dónal  · 技术社区  · 14 年前

    如果我理解正确,broswer会根据文件名缓存图像、JS文件等。因此,如果(在服务器上)更新了一个这样的文件,浏览器将使用缓存的副本,这是一种危险。

    foo.js -> foo_AS577688BC87654.js
    me.png -> me_32126A88BC3456BB.png
    

    但是,除了重命名文件本身之外,还必须更改对这些文件的所有引用。对于exmaple,标记如下 <img src="me.png"/> 应改为 <img src="me_32126A88BC3456BB.png"/>

    有更好的解决办法吗?

    11 回复  |  直到 14 年前
        1
  •  16
  •   PJP    14 年前

    最好的解决方案似乎是通过添加上次修改的时间来对文件名进行版本设置。

    您可以这样做:向Apache配置添加重写规则,如下所示:

    RewriteRule ^(.+)\.(.+)\.(js|css|jpg|png|gif)$ $1.$3
    

    这会将任何“版本化”的URL重定向到“正常”的URL。这样做的目的是保持文件名不变,但从缓存中获益。对于一些不缓存带有参数的URL的代理,将参数附加到URL的解决方案将不是最优的。

    <img src="image.png" />
    

    <img src="<?php versionFile('image.png'); ?>" />
    

    versionFile()如下所示:

    function versionFile($file){
        $path = pathinfo($file);
        $ver = '.'.filemtime($_SERVER['DOCUMENT_ROOT'].$file).'.';
        echo $path['dirname'].'/'.str_replace('.', $ver, $path['basename']);
    }
    

    就这样!浏览器会要求image.123456789.png,Apache会将其重定向到image.png,因此您在任何情况下都会受益于缓存,不会有任何过时的问题,同时不必麻烦文件名版本控制。

    http://particletree.com/notebook/automatically-version-your-css-and-javascript-files/

        2
  •  9
  •   NakedBrunch    14 年前

    为什么不添加一个querystring“version”编号并每次更新版本?

    foo.js->foo.js?版本=5

        3
  •  6
  •   Paul Bevis    14 年前

    重命名您的资源是一种方法,尽管我们使用内部版本号并将其嵌入到文件名中,而不是MD5哈希

    foo.js -> foo.123.js
    

    因为这意味着您的所有资源都可以以确定性的方式重命名并在运行时解析。

        4
  •  3
  •   pjmorse    14 年前

    我们遵循与PJP类似的模式,使用Rails和Nginx。

    我们希望用户的头像图像被浏览器缓存,但当头像发生变化时,我们需要缓存尽快失效。

    return "/images/#{sourcedir}/#{user.login}-#{self.updated_at.to_s(:flat_string)}.png"
    

    在代码中使用化身的所有地方,我们都引用了这个方法而不是URL。在Nginx配置中,我们添加了以下重写:

    rewrite "^/images/avatars/(.+)-[\d]{12}.png"    /images/avatars/$1.png;
    rewrite "^/images/small-avatars/(.+)-[\d]{12}.png"      /images/small-avatars/$1.png;
    

    这意味着如果一个文件改变了,它在HTML中的URL也会改变,因此用户的浏览器会对该文件发出一个新的请求。当请求到达Nginx时,它被重写为文件的简单名称。

        5
  •  3
  •   Gintautas Miliauskas    14 年前

    我建议在这种情况下使用etag缓存,请参见 http://en.wikipedia.org/wiki/HTTP_ETag . 然后可以使用hash作为etag。仍将为每个资源提交请求,但浏览器将仅下载自上次下载以来已更改的项目。

    阅读您的web服务器/平台文档,了解如何正确使用etag,大多数体面的平台都有内置的支持。

        6
  •  2
  •   Moses    14 年前

    大多数现代浏览器在HTTP请求中有可缓存资源时都会检查if-modified-since头。但是,并非所有浏览器都支持if-modified-since头。

    方案1 创建版本为#的查询字符串。 src="script.js?ver=21" . 缺点是许多代理服务器不会缓存带有查询字符串的资源。它还需要站点范围内的更改更新。

    方案2 为文件创建命名系统 src="script083010.js"

    方案3 也许是最优雅的解决方案,只需设置缓存头:服务器中的last-modified和expires。这样做的主要缺点是用户可能不得不重新缓存资源,因为这些资源已过期但从未更改。此外,当从多个服务器提供内容时,最后修改的头不能很好地工作。

    下面是一些要查看的资源: Yahoo Google AskApache.com

        7
  •  2
  •   Bob    14 年前

    ExpiresDefault "access plus 10 years" 在Apache配置中)。否则,浏览器将根据修改的时间和/或Etag进行条件GET。您可以使用web代理或Firebug(在Net面板上)之类的扩展来验证站点上发生了什么。你的问题没有提到你的web服务器是如何配置的,以及它用静态文件发送什么头文件。

        8
  •  1
  •   Adam Butler    14 年前

    我也一直在考虑这个网站,我支持它将是一个大的工作,改变所有的参考。我有两个想法:

    设置远程缓存过期标头,并将建议的更改应用于最常下载的文件。对于其他文件,设置头文件,使其在很短的时间(如10分钟)后过期。然后,如果在更新应用程序时有10分钟的停机时间,那么当用户访问该站点时,缓存将被刷新。一般的网站导航应该改进,因为文件将只需要下载每10分钟,而不是每次点击。

    2 每次将应用程序的新版本部署到包含版本号的不同上下文时。如。www.site.com/app_2_6_0/ 我真的不确定这一点,因为用户的书签将打破每次更新。

        9
  •  1
  •   thomasfedb    14 年前

    我认为多种解决方案的结合最有效:

      • 你的静态“About”、“Contact”等页面一年的变化可能不会超过几次,因此你可以很容易地在这些页面上放置一个月的缓存时间。
      • 这些页面中使用的图像可能会有永久的缓存时间,因为您更喜欢替换图像,而不是更改图像。
    1. 有些东西永远不应该缓存,新页面,用户内容等在这些情况下,你应该缓存在服务器上,但决不能在客户端。

        10
  •  1
  •   xcut    14 年前

    您可能想查看grails“uiperformance”插件所采用的方法,您可以找到 here

    另外,从ui性能页面中,阅读以下内容 14 rules .

        11
  •  1
  •   Mayank Jain    12 年前

    根据 http://httpd.apache.org/docs/2.0/mod/core.html#fileetag

    只需在(/etc/apache2/apache2.conf)中启用它

    FileETag Size
    

    &

    这样,你就可以简单地引用你的图片 <img src='/path/to/foo.png' /> 并且仍然使用HTTP缓存的所有优点。