Apache mod_expires

Apache mod_expires

我对整个访问和修改感到相当困惑。

我希望文件被缓存,直到它们被修改。如果数据相同,则显示缓存版本。如果数据已更改,则下载更新版本并缓存它。

我不明白你为什么想要不同的东西?所有这些访问权限加上 6 个月对我来说毫无意义。如果上次修改日期比缓存日期更新,则请求新文件。难道不能以如此简单的方式完成吗?

我希望能够在 2012 年 1 月 1 日创建 index.html 并让每个人都缓存它。我不希望在我编辑它之前再次下载它。假设我在 2012 年 1 月 5 日编辑它,然后有人自 2012 年 1 月 1 日以来就没有看过 index.html,他们应该看到他们有 2012 年 1 月 1 日的缓存,但现在该文件的最后修改时间为 2012 年 1 月 5 日,因此他们下载 2012 年 1 月 5 日的版本并缓存它。

我绝不希望编辑某些内容后用户在一段时间内都看不到。我希望所有编辑内容都能在下次请求时被查看到。

我如何对所有文件执行此操作?

答案1

什么也不要做。Apache 已经具备了您期望的开箱即用行为。

当浏览器请求已查看并缓存的 URL 时,如果用户未明确强制重新加载,则它会包含一个带有If-Modified-Since前一次请求的时间戳的标头。如果服务器确定资产自时间戳以来未发生更改If-Modified-Since,则它只会响应304 Not Modified。(除了时间戳之外,还有另一个ETag用于检查缓存有效性的标头,称为 ,它通过比较内容的哈希值来工作,但这对本次讨论没有任何帮助。)

您唯一需要使用这些mod_expires功能的情况是,当您想要告诉浏览器在一段时间内不要费心发出 HTTP 请求来检查缓存的资产是否是最新的时。例如,您可以有一个方案,其中 CSS 文件位于/style.1.css,并将其后续版本命名为/style.2.css/style.3.css等。在这种情况下,您可以通过设置标头来完全节省 HTTP 请求的开销Expires

答案2

这里有两个概念:缓存和节省带宽。对于您的用例,我会忘记Expires:,但我稍后会解释它。

如果你从文件夹中提供物理文件,则 Web 服务器将添加一个或两个标头:

  • ETag: xyzzas4324@asdad/33:作为该文件版本的 ID,如果文件内容发生变化,它也会随之变化;和/或
  • Last-Modified: <date>:与文件属性中显示的修改日期相同。

因此下一次,浏览器会稍微修改一下请求 http://$URL/file :

  • If-None-Match: xyzzas4324@asdad/33;和/或
  • If-Modified-Since: <same date>

如果文件没有被改变,服务器就会发回一个304 Not Modified信号给浏览器,让它显示缓存的版本。

注意:这只能避免重复传输该特定文件;浏览器仍然需要等待网络服务器的答复。因此仍然会存在一定的延迟。

这就是问题Expires所在。假设请求的文件是 RSS 源。如果有标Expires: <2 hours from now>头,请求将不是在该时间间隔内由该浏览器重复执行。浏览器无需等待服务器,负载也不会增加。

有一本书对此进行了更详细的介绍:《构建可扩展网站》。它对这些技巧进行了更详细的介绍,但我将简要介绍一下:

这是你应该如何从旧标志更改为新标志,假设你已经设置了Expires: <6 years>整个assets/*

index.htmlv1:

<h1>Welcome to Example Inc!</h1>
<img src="assets/logo_v1.jpg">

index.htmlv2:

<h1>Welcome to Example Inc!</h1>
<img src="assets/logo_v2.jpg">

请注意index.html 没有 Expires: <6 years>。它得到了304 Not Modified处理。当您更改其中一项资产时,您会增加其版本号并更改使用它的 .html 文件。

这样您就可以同时享受两全其美的优势。

答案3

您所描述的期望是任何现代网络服务器默认的工作方式。

如果你不要每次用户请求页面/资产(资产 = js、css、图像等)时,发送显式缓存/过期标头(或者如果您发送 etag 标头),浏览器将向您的服务器发送请求。根据您的描述,这是您想要的行为 - 您希望浏览器始终请求页面/资产并接收更新的内容或304 Not Modified空响应,表明用户之前缓存的是最新版本。

因此,您要做的是删除您自己添加的所有标头,以便 apache 仅根据最后修改的标头做出响应。

至于为什么你想要不同的行为:

上述方法适用于 html 页面 - 但对于很少更改的内容类型或内容更改时只需更改 url 即可,这种方法效率低下。向服务器发送请求并接收响应304 Not Modified并非免费 - 它需要时间(取决于页面上有多少资产 - 这可能需要很长时间)并产生服务器负载(是的,处理大量静态资产请求会显著影响服务器的性能),因此这对用户和您来说都是不利的。这就是为什么您需要添加长过期标头并使用缓存破坏尽可能将 http 请求减少到最低限度,但当资产发生变化时强制用户重新下载。

有一个出色的 .htaccess 指南可从html5boilerplate 项目。它详细介绍了如何优化(缓存)标头以提高性能和用户体验。不过,您不需要纠结于细节:只需放下默认 .htaccess在您的文档根目录中检查它是否按预期运行。默认配置应该完全符合您的要求,并且还具有为静态资产添加最佳实践缓存标头的额外好处。如果您的问题实际上不是关于 html 内容而是其他内容类型 - 请先阅读参考资料,然后再简单地禁用 .htaccess 文件中的缓存逻辑为您完成的所有良好工作;)

相关内容