【问题标题】:Cache Expire Control with Last Modification具有上次修改的缓存过期控制
【发布时间】:2010-10-08 10:44:58
【问题描述】:

在 Apache 的 mod_expires 模块中,Expires 指令具有两个基本时间段,访问修改

ExpiresByType text/html "access plus 30 days"

可以理解的是,缓存将在 30 天后请求新内容。

然而,

ExpiresByType text/html "modification plus 2 hours"

没有直观意义。

浏览器缓存如何知道文件已被修改,除非它向服务器发出请求?如果它正在调用服务器,那么缓存这个指令有什么用?在我看来,我不了解缓存的某些关键部分。请赐教。

【问题讨论】:

    标签: apache caching browser mod-expires


    【解决方案1】:

    以“修改”为基础的Expires* 指令指的是服务器上文件的修改时间。因此,如果您设置“修改加 2 小时”,则任何在文件修改后 2 小时内(在服务器上)请求内容的浏览器都会缓存该内容,直到文件修改时间后 2 小时。并且浏览器知道那个时间是什么时候,因为服务器发送了一个带有正确过期时间的Expires 标头。

    让我用一个例子来解释一下:假设你的 Apache 配置包括这一行

    ExpiresDefault modification plus 2 hours
    

    并且您在服务器上有一个文件index.htmlExpiresDefault 指令适用于该文件。假设您在格林威治标准时间 9:53 上传了 index.html 的一个版本,覆盖了之前存在的 index.html(如果有的话)。所以现在index.html的修改时间是格林威治标准时间9:53。如果您在服务器上运行 ls -l(或在 Windows 上运行 dir),您会在列表中看到它:

    -rw-r--r--  1 apache apache    4096  Feb 18 09:53 index.html
    

    现在,对于每个请求,Apache 都会发送带有文件最后修改时间的 Last-Modified 标头。由于您有 ExpiresDefault 指令,它还将发送 Expires 标头,时间等于文件的修改时间 (9:53) 加上两个小时。所以这是浏览器看到的部分内容:

    Last-Modified: Wed, 18 Feb 2009 09:53:00 GMT
    Expires: Wed, 18 Feb 2009 11:53:00 GMT
    

    如果浏览器发出此请求的时间在格林威治标准时间 11:53 之前,浏览器将缓存该页面,因为它尚未过期。因此,如果用户在格林威治标准时间 11:00 首次访问该页面,然后在格林威治标准时间 11:30 再次访问同一页面,浏览器将看到其缓存版本仍然有效并且不会(或者更确切地说,允许不) 发出一个新的 HTTP 请求。

    如果用户在格林威治标准时间 12:00 第三次访问该页面,浏览器会发现其缓存版本现已过期(在 11:53 之后),因此它会尝试验证该页面,并向服务器发送请求带有 If-Modified-Since 标头。将返回没有正文的 304(未修改)响应,因为该页面的日期自首次提供以来未更改。由于过期日期已过 - 页面“陈旧” - 每次访问该页面时都会发出验证请求,直到验证失败。

    现在,让我们假设您在 11:57 上传了新版本的网页。在这种情况下,浏览器在 12:00 尝试验证页面的旧版本失败,它会在响应中收到与新页面一起的以下两个新标头:

    Last-Modified: Wed, 18 Feb 2009 11:57:00 GMT
    Expires: Wed, 18 Feb 2009 13:57:00 GMT
    

    (新版本上传后文件最后修改时间变为11:57,Apache计算过期时间为11:57 + 2:00 = 13:57 GMT。)

    现在直到 13:57 才需要验证(使用最近的日期)。

    (当然请注意,我上面列出的两个标头会同时发送许多其他内容,为简单起见,我只是删除了所有其他内容)

    【讨论】:

    • 嗨大卫,这是有道理的,但我仍然不确定,服务器为什么以及如何知道发送浏览器。因此,如果我理解正确,下次浏览器请求资源时,服务器会以某种方式向浏览器发送有关文件修改状态的信息——但这不是一个获取
    • 我想用一个例子来解释这个最容易,所以我在...中编辑了一个。
    • 重点是当您说the browser will see that its cached version is still valid and will not (or rather, is allowed not to) make a new HTTP request 时,“或者更确切地说不允许”是什么意思???因为我打开了另一个关于缓存问题的问题,并且似乎甚至在很远的将来使用了过期日期,所以该死的浏览器通过发出 HTTP 请求来向服务器查询更新版本而不是从缓存中获取它的行为相同,请参阅:stackoverflow.com/questions/10048740/…
    • @Marco 这正是我所说的,HTTP 规范不要求浏览器在任何情况下都使用其缓存版本。
    • 感谢您的回复,但我现在真的不明白。为什么谷歌建议所有这些 mod_expires 东西利用浏览器缓存 developers.google.com/speed/docs/best-practices/caching ,如果浏览器最后不遵循服务器指令来缓存东西并且仍然返回向服务器发出 HTTP 请求,它被告知要缓存很长时间?
    【解决方案2】:

    服务器发送一个标头,例如:“Last-Modified: Wed, 18 Feb 2009 00:00:00 GMT”。缓存的行为基于此标头或访问时间。

    说如果内容预计每天刷新,那么你希望它“修改加24小时”过期。

    如果你不知道内容什么时候会刷新,那么最好以访问时间为准。

    【讨论】:

    • 您好安德鲁,感谢您的回答。服务器何时以及多久发送一次 Last Modified 标头?还是在浏览器会话期间发生
    【解决方案3】:

    我的理解是,修改要求浏览器根据 Last-Modificatied HTTP 标头的值来确定缓存时间。因此,修改时间加上 2 小时将是 Last-Modificatied 时间 + 2 小时。

    【讨论】:

      【解决方案4】:

      首先,感谢 David Z 上面的详细解释。在回答 bushman 的问题时,如果仍然需要服务器发出请求,为什么调用缓存是有意义的,答案是时间保存在服务器返回的内容中。如果缓存指令指示文件的内容仍然是新鲜的,则不会返回内容,而是返回 304 代码和空响应正文。这就是节省时间的地方。

      比我给出的更好的解释在这里,来自https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers

      虽然条件请求确实会通过网络调用调用,但未修改的资源会导致响应主体为空,从而节省了将资源传输回最终客户端的成本。后端服务通常还能够非常快速地确定资源的最后修改日期,而无需访问资源本身,这节省了非常重要的处理时间。

      基于时间

      基于时间的条件请求确保仅当请求的资源在浏览器的副本被缓存后发生更改时,才会传输内容。如果缓存的副本是最新的,则服务器返回 304 响应代码。

      为了启用条件请求,应用程序通过 Last-Modified 响应标头指定资源的最后修改时间。

      缓存控制:公共,最大年龄=31536000 最后修改时间:2011 年 1 月 3 日星期一 17:45:57 GMT

      下次浏览器请求该资源时,它只会使用 If-Modified-Since 请求标头询问资源的内容(如果它们自此日期以来未更改)

      If-Modified-Since:星期一,2011 年 1 月 3 日 17:45:57 GMT

      如果自格林威治标准时间 2011 年 1 月 3 日星期一 17:45:57 以来资源未更改,则服务器将返回带有 304 响应代码的空正文。

      【讨论】:

        猜你喜欢
        • 2013-02-10
        • 2016-04-15
        • 1970-01-01
        • 1970-01-01
        • 2011-12-14
        • 1970-01-01
        • 1970-01-01
        • 2011-05-25
        • 1970-01-01
        相关资源
        最近更新 更多