当客户端决定检索资源时,RFC2616管理该资源是否可以从缓存返回或需要从源服务器重新验证/重新加载的规则(主要是第 14.9 节,但您确实需要阅读整个内容) .
但是,当您在同一页面上有同一资源的多个副本时,在按照 RFC2616 的规则检索到第一个副本之后,关于是否检索其他副本的决定现在由 HTML5 规范(主要在获取资源的处理模型)。
特别要注意第 10 步:
如果资源 [...] 由于其他原因已经被下载(例如该算法的另一个调用),并且此请求将与前一个请求相同(例如相同的 Accept 和 Origin 标头),并且用户代理配置为即重用现有下载中的数据而不是开始新的下载,然后使用现有下载的结果而不是开始新的下载。
这清楚地描述了在决定是否可以重用资源时可能发挥作用的许多因素。一些关键点:
相同的 Accept 和 Origin 标头:虽然大多数浏览器在Accept
任何地方都使用相同的标头,但在 Internet Explorer 中,对于图像、脚本和 HTML,它们是不同的。Referer
并且每个浏览器在涉及帧时都会发送不同的内容,并且Referer
没有直接提及,Accept
仅Origin
作为示例给出。
已经下载:请注意,这与已经下载的内容完全不同。因此,如果资源在页面上多次出现,但第一次出现在遇到第二次出现之前完成下载,则重用选项可能不适用。
用户代理被配置为重用数据:这对我来说意味着重用或重新检索数据的决定在某种程度上取决于用户代理,或者至少是用户选项。
最终结果是,每个浏览器处理缓存的方式都略有不同。即使在特定的浏览器中,结果也可能因时间而异。
我创建了一个包含三个嵌套框架的测试用例(即一个包含 的页面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 个。虽然
Accept
Chrome 中的图像和脚本的标头是相同的,但标头顺序不同,这表明它们可能会受到不同的处理,并且可能会以不同的方式缓存。
- Internet Explorer 加载了 2 个副本,每种类型各 1 个,这是他们所期望的。假设这可能会有所不同,因为它们只是脚本时的行为。
- Safari 仍然只有 3 个副本,每帧一个。
- Opera 莫名其妙地还是 6。无法分辨其中哪些部分是脚本,哪些是图像。但这也可能会因负载或时间而异。
- Firefox 加载了 8 个副本,这对他们来说是意料之中的。6 个脚本,加上 2 个新图像。
现在这就是正常查看页面时发生的情况 - 即只需在地址栏中输入页面 url。使用 F5(或 Safari 上的任何等效项)强制重新加载会产生一组完全不同的结果。总的来说,重新加载的整个概念,F5 与 Ctrl-F5,客户端发送什么标头等也因浏览器而异。但这是另一天的主题。
底线是缓存从一个浏览器到另一个浏览器是非常不可预测的,并且规范在某种程度上让实现者决定什么对他们最有效。
我希望这已经回答了你的问题。
附加说明:我应该提一下,我并没有竭尽全力测试每个浏览器的最新副本(特别是 Safari 是一个古老的 v4,Internet Explorer 是 v9,但其他浏览器可能是最新的)。我怀疑它有很大的不同。在这方面,所有浏览器突然收敛到一致行为的可能性极小。