15

在 Apache 的mod_expires模块中,有Expires两个基本时间段的指令accessmodify

ExpiresByType text/html "access plus 30 days"

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

然而,

ExpiresByType text/html "modification plus 2 hours"

没有直觉意义。

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

4

4 回答 4

41

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

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

ExpiresDefault modification plus 2 hours

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

-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 才需要验证(使用最近的日期)。

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

于 2009-02-18T21:50:54.273 回答
4

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

假设内容预计每天都会刷新,那么您希望它“修改加 24 小时”过期。

如果你不知道什么时候刷新内容,那么最好根据访问时间来确定。

于 2009-02-18T21:29:03.560 回答
0

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

于 2009-02-18T21:00:58.730 回答
0

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

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

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

基于时间

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

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

Cache-Control:public, max-age=31536000 Last-Modified: Mon, 03 Jan 2011 17:45:57 GMT

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

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

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

于 2014-10-09T21:32:07.683 回答