【问题标题】:How to set up caching for css/js static properly如何正确设置 css/js 静态缓存
【发布时间】:2011-10-11 23:56:09
【问题描述】:

为了防止出现问题,当我更新 CSS/JS 媒体文件并且浏览器不请求新版本时,因为它们缓存了这些文件,我使用了这个解决方案:https://github.com/jaddison/django-cachebuster,将 ? 添加到 CSS/JS 文件名(将 /media/main.css 替换为 /media/main.css?20012931203128。我认为它会在时间戳更改(文件已更新)时强制浏览器重新加载 css 文件,并在其他情况下使用本地缓存版本。但我所看到的在 Apache 日志中(以及在 firebug 中)是浏览器(至少是 Firefox)为页面的每次重新加载请求 CSS/JS 文件,即使在获得 304 代码之后,请参阅日志中的片段:

XXX.255.115.60 - - [24/Jul/2011:04:17:25 -0700] "GET /media/main.css?333900240611 HTTP/1.1" 304 172 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XXX.255.115.60 - - [24/Jul/2011:04:17:26 -0700] "GET /media/main.js?270101180511 HTTP/1.1" 304 173 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XXX.255.115.60 - - [24/Jul/2011:04:17:34 -0700] "GET /media/main.css?333900240611 HTTP/1.1" 304 172 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XXX.255.115.60 - - [24/Jul/2011:04:17:35 -0700] "GET /media/main.js?270101180511 HTTP/1.1" 304 173 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XXX.255.115.60 - - [24/Jul/2011:04:17:44 -0700] "GET /media/main.css?333900240611 HTTP/1.1" 304 172 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"
XXX.255.115.60 - - [24/Jul/2011:04:17:44 -0700] "GET /media/main.js?270101180511 HTTP/1.1" 304 173 "" "Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"

当然,这会使我的网站变慢。是否可以仅在 .css?... 之后的时间戳更改时强制浏览器更新文件? 谢谢!

更新: 以下是响应和请求的示例:

请求

User-Agent  Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.2.18) Gecko/20110614 Firefox/3.6.18
Accept  text/css,*/*;q=0.1
Accept-Language en-gb,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive  115
Referer 
DNT 1
Connection  keep-alive
If-Modified-Since   Fri, 24 Jun 2011 05:39:33 GMT
If-None-Match   "8ed02f1-a21-4a66ea04f2f40"

回应

Date    Sun, 24 Jul 2011 12:28:21 GMT
Server  Apache
Connection  Keep-Alive
Keep-Alive  timeout=2, max=99
Etag    "8ed02f1-a21-4a66ea04f2f40"

初始响应

Date    Sun, 24 Jul 2011 12:51:05 GMT
Server  Apache
Last-Modified   Fri, 24 Jun 2011 05:39:33 GMT
Etag    "8ed02f1-a21-4a66ea04f2f40"
Accept-Ranges   bytes
Content-Length  2593
Keep-Alive  timeout=2, max=99
Connection  Keep-Alive
Content-Type    text/css

【问题讨论】:

  • 这样一个请求的响应头是什么样子的?
  • Gumbo,我用这些细节更新了一个原始问题。
  • 对初始请求的响应如何?
  • 您在谈论获取页面的响应(不是页面组件?)它看起来像这样 日期 Sun, 24 Jul 2011 12:44:45 GMT 服务器 Apache Vary Cookie,Accept-Encoding Set-Cookie csrftoken=...;最大年龄=31449600;路径=/ sessionid=...; expires=星期日,2011 年 8 月 7 日 12:44:46 GMT;最大年龄=1209600; Path=/ Content-Encoding gzip Content-Length 2294 Keep-Alive timeout=2, max=100 Connection Keep-Alive Content-Type text/html; charset=utf-8
  • 我的意思是在请求被缓存之前的响应。您显示的请求/响应已经是验证已缓存响应的条件请求。

标签: apache caching browser client-side


【解决方案1】:

您应该使用正确的HTTP caching 指令来做出响应never expire(未来一年):

Cache-Control: max-age=31536000
Expires: Sun, 24 Jul 2012 12:51:05 GMT

您可以在 Apache 中使用mod_expires

ExpiresByType text/css "now plus 1 year"
ExpiresByType text/javascript "now plus 1 year"

【讨论】:

  • 恐怕这无济于事。正如我在回答中所写,我认为问题出在其他地方。缓存或不缓存的决定不在浏览器中,而在 Apache 的行为中。如果我记得我想我尝试过类似的东西,那是一条死胡同。
  • @Tomas Telensky:不,是客户端决定是否缓存响应。它是根据请求/响应来完成的。
  • 好吧,但是如果有一个查询字符串,浏览器必须总是询问服务器,因为如果它不是动态生成的,它现在不会。然后由服务器正确响应,但 Apache 没有 - 请参阅我的答案。
  • 嗨 Gumbo,我向您推荐了,现在最初的答案是 dumpz.org/69932,但我仍然在 apache 日志中看到对 js/css 文件的请求。有趣的是,响应大小是 100-200 字节,这意味着文件没有被传输(我猜,只有 304 代码),但是浏览器不理解,它不应该查询这些文件。
  • ... 完全符合我的预期 :-)
【解决方案2】:


我玩了很多次,发现它可能是由 Apache bug 引起的。这不是浏览器的问题——一旦timesatmp 在查询字符串中,浏览器就不能理解查询字符串并且必须至少询问服务器它是否没有改变。 Apache 以“304 Not modified”响应良好,但它也总是发送文件!

我做了很多实验,唯一有效的解决方案是将时间戳直接放在文件名中。在 PHP 中,我使用以下函数:

function safe_inline_url($file)
{

     $basename = basename($file);
     if (strstr($basename, '.'))
          return dirname($file) . "/" .
               preg_replace('/(\.[^\.]*)$/', '_ts_' . filemtime($file) . '\1',
                    $basename);
     else 
          return $file . '_ts_' . filemtime($file);

}

它修改任何内联 URL(css、js、图像、...),以便添加时间戳,例如。比如 js/forms.js => js/forms_ts_1278080148.js .

在服务器上,您必须将修改后的文件名重写回真实名称,这是通过将其放入您的 .htaccess 文件来完成的:

RewriteEngine On

RewriteCond %{REQUEST_URI}      ^(.*)_ts_[0-9]{9,}$
RewriteRule ^                   %1      [PT]

RewriteCond %{REQUEST_URI}      ^(.*)_ts_[0-9]{9,}\.(.*)$
RewriteRule ^                   %1.%2   [PT]

你把它放到根目录,你还必须把它放到每个子目录的 .htaccess 中,并开启 RewriteEngine

唯一的问题是 scriptaculous javascript 库使用 URL 来包含其他来源 - 你不能使用这个技巧来包含他们的 js 文件。

【讨论】:

  • 谢谢,托马斯。我也想过,django-cachedbuster中没有包含这个方法,所以我更喜欢在写自己的代码之前先问一下:)
  • 好吧,我推荐使用这个,它对我有用好几年(例如,参见birds.cz)。
猜你喜欢
  • 2012-09-19
  • 1970-01-01
  • 2011-02-01
  • 2014-02-22
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
  • 2011-10-04
相关资源
最近更新 更多