3

这篇Yahoo Developer Network 文章说,浏览器以不同的方式处理在单个 HTML 中多次引用的不可缓存资源。我在HTTP/1.1 缓存 RFC中没有找到任何关于此的规则。

我在 Chrome 中做了一些实验,但我无法弄清楚确切的规则。它只加载了一次重复的不可缓存脚本标签。然后我在 3 个 iframe 中引用了相同的脚本。第一个触发了网络请求,但其他请求是从缓存中提供的。我试图引用与图像的 src 相同的 url,这再次触发了网络请求。

有没有关于这种行为的文档?这在浏览器之间有何不同?

4

2 回答 2

3

当客户端决定检索资源时,RFC2616管理该资源是否可以从缓存返回或需要从源服务器重新验证/重新加载的规则(主要是第 14.9 节,但您确实需要阅读整个内容) .

但是,当您在同一页面上有同一资源的多个副本时,在按照 RFC2616 的规则检索到第一个副本之后,关于是否检索其他副本的决定现在由 HTML5 规范(主要在获取资源的处理模型)。

特别要注意第 10 步:

如果资源 [...] 由于其他原因已经被下载(例如该算法的另一个调用),并且此请求将与前一个请求相同(例如相同的 Accept 和 Origin 标头),并且用户代理配置为即重用现有下载中的数据而不是开始新的下载,然后使用现有下载的结果而不是开始新的下载。

这清楚地描述了在决定是否可以重用资源时可能发挥作用的许多因素。一些关键点:

  • 相同的 Accept 和 Origin 标头:虽然大多数浏览器在Accept任何地方都使用相同的标头,但在 Internet Explorer 中,对于图像、脚本和 HTML,它们是不同的。Referer并且每个浏览器在涉及帧时都会发送不同的内容,并且Referer没有直接提及,AcceptOrigin作为示例给出。

  • 已经下载:请注意,这与已经下载的内容完全不同。因此,如果资源在页面上多次出现,但第一次出现在遇到第二次出现之前完成下载,则重用选项可能不适用。

  • 用户代理被配置为重用数据:这对我来说意味着重用或重新检索数据的决定在某种程度上取决于用户代理,或者至少是用户选项。

最终结果是,每个浏览器处理缓存的方式都略有不同。即使在特定的浏览器中,结果也可能因时间而异。

我创建了一个包含三个嵌套框架的测试用例(即一个包含 的页面iframe,它本身包含一个iframe)和相同脚本的 6 个副本,每个页面上有 2 个(Cache-Control:no-cache用于使它们不可缓存,但也使用其他变体进行测试,包括max-age=0)。

  • Chrome 仅加载了 1 个副本。
  • Internet Explorer 倾向于变化,假设基于负载,但在 1 到 3 之间。
  • Safari 加载了 3 个副本,每个帧一个(即具有不同的Referer标题)。
  • Opera 和 Firefox 加载了所有 6 个副本。

当我在几个图像(一个在根页面,一个在第一个iframe)和其他几个图像中重复使用相同的资源以供参考时,行为发生了变化。

  • Chrome 现在加载了 5 个副本,每个页面上每种类型 1 个。虽然AcceptChrome 中的图像和脚本的标头是相同的,但标头顺序不同,这表明它们可能会受到不同的处理,并且可能会以不同的方式缓存。
  • Internet Explorer 加载了 2 个副本,每种类型各 1 个,这是他们所期望的。假设这可能会有所不同,因为它们只是脚本时的行为。
  • Safari 仍然只有 3 个副本,每帧一个。
  • Opera 莫名其妙地还是 6。无法分辨其中哪些部分是脚本,哪些是图像。但这也可能会因负载或时间而异。
  • Firefox 加载了 8 个副本,这对他们来说是意料之中的。6 个脚本,加上 2 个新图像。

现在这就是正常查看页面时发生的情况 - 即只需在地址栏中输入页面 url。使用 F5(或 Safari 上的任何等效项)强制重新加载会产生一组完全不同的结果。总的来说,重新加载的整个概念,F5 与 Ctrl-F5,客户端发送什么标头等也因浏览器而异。但这是另一天的主题。

底线是缓存从一个浏览器到另一个浏览器是非常不可预测的,并且规范在某种程度上让实现者决定什么对他们最有效。

我希望这已经回答了你的问题。

附加说明:我应该提一下,我并没有竭尽全力测试每个浏览器的最新副本(特别是 Safari 是一个古老的 v4,Internet Explorer 是 v9,但其他浏览器可能是最新的)。我怀疑它有很大的不同。在这方面,所有浏览器突然收敛到一致行为的可能性极小。

于 2013-05-09T19:09:17.650 回答
1

Molnarg,如果您正确阅读这篇文章,就会清楚为什么会发生这种情况。

不必要的 HTTP 请求发生在 Internet Explorer 中,但不会发生在 Firefox 中。在 Internet Explorer 中,如果一个外部脚本被包含两次并且不可缓存,它会在页面加载期间生成两个 HTTP 请求。即使脚本是可缓存的,当用户重新加载页面时也会出现额外的 HTTP 请求。

此行为仅 Internet Explorer 独有。如果你问我为什么会这样,我会说 IE 开发人员选择忽略HTTP/1.1 缓存 RFC,或者至少无法实现它。也许这是一项正在进行的工作。但话又说回来,IE 在很多方面与大多数浏览器(JavaScript、HTML5、CSS)不同。除非开发人员更新它,否则这无济于事。

您提供的 Yahoo Dev Article列出了高性能的最佳实践。这必须适应所有受此影响的 IE 用户。这就是为什么多次包含相同的脚本的原因,尽管对于其他浏览器来说 OK 会伤害 IE 用户并且应该避免。

更新

不可缓存的资源将生成网络请求,一次或多次。

来自2.来自HTTP/1.1 缓存 RFC的缓存操作概述

尽管缓存是 HTTP 的一个完全可选的特性,但我们假设重用缓存的响应是可取的,并且当没有要求或本地所需的配置阻止它时,这种重用是默认行为。

因此,使用缓存意味着尝试重用,而不可缓存意味着相反。把它想象成这个不可缓存的请求就像关闭缓存的 HTTP 请求(从打开缓存的 HTTP 回退)。

Cache-Control: max-age=n 不会阻止缓存存储它只是说明缓存项在 n 秒后是陈旧的。为防止使用缓存,请为图像使用这些标头:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
于 2013-05-07T15:44:02.520 回答