【问题标题】:Stop browser to make HTTP requests for images that should stay cached - mod_expires停止浏览器以对应保持缓存的图像发出 HTTP 请求 - mod_expires
【发布时间】:2012-04-20 09:09:42
【问题描述】:

在阅读了这里的许多文章和一些问题后,我终于成功激活了 Apache mod_expires 告诉浏览器它必须缓存图像 1 年

<filesMatch "\.(ico|gif|jpg|png)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 year"
  Header append Cache-Control "public"
</filesMatch>

谢天谢地,服务器响应似乎是正确的:

HTTP/1.1 200 OK 
Date: Fri, 06 Apr 2012 19:25:30 GMT 
Server: Apache 
Last-Modified: Tue, 26 Jul 2011 18:50:14 GMT 
Accept-Ranges: bytes 
Content-Length: 24884 
Cache-Control: max-age=31536000, public 
Expires: Sat, 06 Apr 2013 19:25:30 GMT
Connection: close
Content-Type: image/jpeg 

好吧,我认为这会阻止浏览器下载,甚至会在 1 年内向服务器查询图像。但这部分是正确的:因为如果您关闭并重新打开浏览器,浏览器将不再从服务器下载图像但浏览器仍会向服务器查询每个图像的 HTTP 请求强>.

如何强制浏览器停止对每张图片发出 HTTP 请求?即使这些 HTTP 请求之后没有下载图像,它们仍然是向服务器发出的请求,这会不必要地增加延迟并减慢页面呈现速度!

我已经告诉浏览器它必须将图像缓存 1 年!为什么浏览器仍然会查询服务器的每张图片(即使它没有下载图片)?!


查看 FireBug 中的网络图(菜单 FireBug > Net > Images)我可以看到不同的缓存行为(我显然从浏览器缓存完全为空开始,我使用“清除所有历史记录”强制在浏览器上删除缓存):

  • 第一次加载页面时,所有图像都已下载(如果我通过单击浏览器的重新加载页面按钮强制重新加载页面,也会发生同样的事情)。 这是有道理的!

  • 当我浏览网站并返回同一页面时根本没有下载图像,浏览器甚至不会向服务器查询任何内容的图像。 这是有道理的,(我希望在浏览器关闭时也能看到这种行为)!

  • 1234563 HTTP请求,就像浏览器向服务器询问图片(服务器回复200 OK)。 这是让我恼火的一个!

如果您有兴趣,我还附上下面的图表:

编辑:刚刚也使用 FireFox 11.0 进行了测试,以确保这不是我的 FireFox 3.6 太旧的问题。同样的事情发生!!! 我还测试了 Google 网站和 Stackoverflow 网站,它们都发送了 Cache-Control: max-age=...,但是 一旦浏览器关闭并再次打开,浏览器仍然会为每个图像向服务器发出 HTTP 请求同一页面,在服务器响应后,浏览器不会下载图像(正如我上面解释的那样),但它仍然发出该死的请求,增加了查看页面的时间。

EDIT2:按照here 的建议删除Last-Modified 标头,并没有解决问题,也没有任何区别。

【问题讨论】:

  • 如果可能更新,默认行为是下载?
  • @Tont Hopkinson:但我告诉浏览器ExpiresDefault "access plus 1 year"(即Cache-Control: max-age=31536000)所以浏览器不应该再次访问服务器询问/寻找此类资源,我已经告诉他保留它缓存 1 年形成最后一次访问。
  • 这就是为什么你所做的工作如你所愿是吗? Expires 是从浏览器缓存中删除的,不要不检查缓存是否更新一年......
  • @Tony Hopkinson:对不起,我没听懂你的意思。我希望浏览器不要下载图像,甚至不要再查询服务器 1 年。从我的测试来看,浏览器似乎没有再次下载图像,但它仍然查询服务器。我希望浏览器能够从自己的缓存中获取图像,并且在 1 年内不再访问服务器。
  • 需要注意的是,无论设置了什么标头,当您刷新浏览器时都会发出实际的 http 请求。服务器仍会以 304 响应,并且不会有多少字节通过网络传输,但您仍然会遇到延迟问题。当跟随链接和导航时,浏览器本地缓存被命中(没有http请求)。只是调试时需要注意的事情。

标签: caching browser http-headers mod-expires


【解决方案1】:

您看到的行为是预期的(有关更多详细信息,请参阅RFC7234),指定的行为:

无论缓存状态如何,所有现代浏览器都会针对显示的每个页面元素向服务器发送 HTTP 请求。这是应网络服务(尤其是广告网络)的要求做出的设计决策,以确保 HTTP 服务器能够维护每个元素的每次显示的记录。

如果浏览器没有发出这些请求,服务器将永远不会收到图像已显示给用户的通知。对于广告网络来说,这将是灾难性的。早期,广告网络通过使用随机生成的名称(例如:'coke_ad_1_98719283719283.gif')提供相同的广告图像来绕过这个问题。然而,对于 ISP 而言,这种做法导致数据传输量大幅增加,因为他们的每个用户都在重新下载这些相同的广告图片,绕过他们 ISP 运行的任何缓存/代理服务器。

因此达成了休战:浏览器总是会发送 HTTP 请求,即使对于未过期的缓存元素也是如此。服务器将响应 HTTP 304 状态代码(“未修改”)。这允许服务器记录图像显示给客户端的事实。因此,广告网络一般停止使用随机图像名称来绕过网络缓存服务器。

这为广告网络提供了他们想要的东西 - 显示的每张图像的记录 - 并为 ISP 提供了他们想要的东西 - 可缓存的图像和静态内容。

这就是为什么您无法阻止浏览器发送对缓存页面元素的 HTTP 请求的原因。

但是,如果您查看与 html5 一起提供的其他可用客户端解决方案,则可以防止资源加载

  1. Cache Manifest(尽管有问题)
  2. IndexedDB(不错的异步功能,允许存储 blob)
  3. Local Storage(非异步)

【讨论】:

  • ...让我吃惊的是,服务器似乎无论如何都被询问了,回复 200 OK。但正如 Peter Lundsby 所解释的(并且根据这个 stackoverflow.com/questions/6797361 ),它可能只是 FireBug 显示请求,但请求是向浏览器 CACHE 发出的,而不是真正向服务器发出的,这就是为什么显示为灰色的原因。
  • Jason,你有任何其他信息的参考吗? — 这很有趣,我一直在寻找这样的东西。
  • -1:这是完全错误的。现代浏览器在缓存到期之前不会重新请求使用正确缓存控制标头发送的图像,但有一些例外情况,例如用户强制重新加载页面。广告问题也可以通过告诉浏览器不要缓存图像来轻松解决。
  • 为了呼应@romkyns 所说的话,除非谷歌和许多其他开发人员在使用服务器重写和版本号来防止服务器命中方面完全错误,否则这个答案是不正确的。
  • 为什么有 35 个人支持这个完全且易于测试的废话? 叹息
【解决方案2】:

您在分析请求时使用了错误的工具。

我推荐真正有用的 Firefox 插件 Live HTTP 标头,这样您就可以了解网络上的真实情况。

并且可以肯定的是,您可以 ssh/putty 您的服务器并执行类似的操作

tail -f /var/log/apache2/access.log

【讨论】:

  • 完全正确!通过使用您建议的工具,我可以看到 HTTP 请求没有按预期再次发送。非常感谢!我不知道为什么“FireBug > Net”会显示所有那些根本没有完成的请求!!!
  • 这在某些时候可能是正确的——但我的萤火虫版本清楚地显示缓存请求为灰色/白色阴影线。分析 apache 日志没有错,但 firebug 也没有错。
【解决方案3】:

“重新加载”和“刷新”是有区别的。只是导航到带有后退和前进按钮的页面通常不会启动新的 HTTP 请求,但特别是按 F5 来“刷新”页面会导致浏览器再次检查其缓存。这取决于浏览器,但似乎是 FF 和 Chrome 的规范(即能够轻松查看其网络流量的浏览器。)按 F6,输入应聚焦 URL 地址栏,然后“转到”它,这应该重新加载页面,但不要仔细检查页面上的资产。

更新:澄清前后导航行为。它在浏览器中称为“Back Forward Cache”或 BFCache。当您使用后退/前进按钮导航时,目的是向您显示与您在自己的时间轴中看到页面时完全相同的页面。使用 back 和 forward 时不会发出服务器请求,即使服务器缓存标头表明特定项目已过期。

如果您在开发者网络面板中看到 (200 OK BFCache),则服务器从未被击中 - 甚至询问 if-modified-since。

http://www.softwareishard.com/blog/firebug/firebug-tip-what-the-heck-is-bfcache/

【讨论】:

  • 多年来,术语“重新加载”和“刷新”在浏览器的用户界面中可以互换使用。我很确定 Netscape Navigator 4 有一个“重新加载”按钮,而 IE 6 有一个“刷新”按钮。在每种情况下,按钮都会向服务器发送一个 HTTP 请求。除此之外,我相信你的回答是正确的。
【解决方案4】:

如果我使用 F5 或 F5 + Ctrl 强制刷新,则会发送请求。但是,如果我关闭浏览器并再次输入 url,则不会发送任何请求。我测试是否发送请求的方法是在服务器上的开始请求上使用断点,即使没有发送请求,它仍然在 Firebug 中显示为已完成 7 毫秒的等待,因此请注意这一点。

【讨论】:

  • 它不起作用,我的意思是它没有任何区别,因为一个人正确地评论了同一篇文章,大卫梅里利斯:"Does this work? I've removed both the Etag and Last-Modified headers, and added an expires header, but it always revalidates with 200 response."
  • 它实际上对我有用!如果我使用 F5 或 F5 + Ctrl 强制刷新,则会发送请求。但是,如果我关闭浏览器并再次输入 url,则不会发送任何请求。我测试是否发送请求的方法是在服务器上的开始请求上使用断点,即使没有发送请求,它仍会在 Firebug 中显示为已等待 7 毫秒,因此请注意这一点。
  • 通过将您的建议替换为您最后的评论来编辑您的答案,我会接受您的回答。我什至发现这很好地解释了你在说什么:stackoverflow.com/questions/6797361/…
【解决方案5】:

您在此处描述的内容并不反映我的经验。如果内容是使用 no-store 指令提供的,或者您进行了显式刷新,那么是的,我希望它返回到原始服务器,否则它应该在浏览器重新启动时被缓存(假设它被允许并且可以写入缓存文件)。

更详细地查看您的瀑布(这很棘手,因为它们有点小且模糊),浏览器似乎正在做它应该做的事情 - 它图像条目 -但这些只是从本地缓存加载,而不是从源服务器加载 - 检查响应中的“日期”标头(为什么您认为它需要毫秒而不是秒?)。这就是为什么它们的颜色不同。

【讨论】:

  • 没错。如果响应已经被缓存,Firebug 会以浅灰色显示请求。要确认,请转到 Firebug > Net > Request URL > Cache。查看获取计数。您应该会看到该字段的增量。
  • 大家感谢您抽出宝贵时间回复。可能我的问题太长了。 FF 从缓存中获取文件是正确的,但关键是在这样做之前它确实联系了服务器。服务器回复 200 OK,FF 不下载文件,从缓存中获取。我对 FF 从缓存中获取文件并不感到惊讶,我对 FF 第一次联系服务器感到惊讶,我已经告诉 FF 文件不会过期Cache-Control: max-age=31536000,那么为什么 FF 会继续联系服务器。每个图像的服务器请求都会增加可观的延迟(即使未下载图像)
  • @symcbean:您可以通过打开此 Stackoverflow 站点(服务器确实发送 Cache-Control max-age=604800)轻松测试此行为,因此图像应缓存 7 天。好吧,如果您浏览 SO 站点,您将在“Firebug > Net”中看到图像http:...stackoverflow/img/tag-adobe.png 甚至没有出现在“Firebug > Net”中,我认为这是因为图像是从缓存中获取的。但是,如果你关闭浏览器并再次打开它,你会在“Firebug > Net”中看到再次联系服务器(灰色)获取这样的图像,然后图像没有下载,但仍然命中了服务器。
  • @Marco:如果你不相信我/firebug,那么使用wireshark 来查看实际发送到服务器的内容。
  • @symcbean: 但是你如何解释在没有关闭浏览器并重新打开浏览器的情况下导航站点时,Firbug > Net 甚至没有显示那些灰色请求?
【解决方案6】:

在自己花费大量时间寻找合理的答案之后,我发现以下链接最有用,它确实回答了这里提出的问题。

https://webmasters.stackexchange.com/questions/25342/headers-to-prevent-304-if-modified-since-head-requests

【讨论】:

    【解决方案7】:

    如果这是生死攸关的问题(如果您想以这种方式优化页面加载,或者无论如何都想尽可能减少服务器上的负载),那么有一种解决方法。

    使用 HTML5 本地存储在第一次请求图像后缓存图像。

    • [+] 您可以阻止浏览器发送 HTTP 请求,无论用户如何努力(F5、ctrl+F5、只是重新访问页面等)

    • [-]您必须为此付出一些额外的努力来支持 javascript。

    • [-] 图像存储在 base64 中(我们无法存储二进制数据),这就是为什么它们每次都在客户端进行解码。这通常相当快而且没什么大不了,但它仍然是客户端的一些额外 cpu 使用,应该牢记。

    • [-] 本地存储空间有限。您可以针对每个域使用约 5mb 的数据(注意:base64 将图像的原始大小增加约 30%)。

    • [?]大部分浏览器都支持。 http://caniuse.com/#search=localstorage

    Example

    Test

    【讨论】:

      【解决方案8】:

      您在 Chrome 中看到的不是实际 HTTP 请求的记录,而是资产请求的记录。 Chrome 这样做是为了向您显示页面实际上正在请求资产。但是,此视图实际上并不能真正指示请求是否正在发出。如果资产被缓存,Chrome 将永远不会真正创建底层 HTTP 请求。

      您还可以通过将鼠标悬停在时间线中的紫色线段上来确认这一点。缓存的资源在工具提示中会有一个(from cache)

      为了查看实际的 HTTP 请求,您需要查看较低的级别。在某些浏览器中,这可以通过插件(如 Live HTTP Headers)来完成。

      但实际上,要验证请求并未真正发出,您需要检查服务器日志或使用 Charles 或 Fiddler 等调试代理。这将在 HTTP 级别上起作用,以确保请求没有实际发生。

      【讨论】:

        【解决方案9】:

        缓存验证和 304 响应

        在多种情况下 Internet Explorer 需要检查缓存条目是否有效:

        • 缓存的条目没有过期日期,并且是在浏览器会话中首次访问内容

        • 缓存的条目有过期日期,但已经过期了

        • 用户已通过单击刷新按钮或按 F5 请求页面更新

        如果缓存条目有最后修改日期,IE 会在 GET 请求消息的 If-Modified-Since 标头中发送它:

        GET /images/logo.gif HTTP/1.1
        Accept: */*
        Referer: http://www.google.com/
        Accept-Encoding: gzip, deflate
        If-Modified-Since: Thu, 23 Sep 2004 17:42:04 GMT
        User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)
        Host: www.google.com
        

        服务器检查 If-Modified-Since 标头并做出相应响应。如果内容自指定的日期/时间以来没有更改,它会回复状态代码 304 和仅包含标题的响应消息:

        HTTP/1.1 304 Not Modified
        Content-Type: text/html
        Server: GWS/2.1
        Content-Length: 0
        Date: Thu, 04 Oct 2004 12:00:00 GMT
        

        响应可以快速下载,因为它不包含内容并导致 IE 从缓存中读取所需的数据。实际上,它就像重定向到本地浏览器缓存。

        如果请求的对象自 If-Modified-Since 标头中的日期/时间以来实际上已更改,则服务器以状态代码 200 响应并提供资源的修改版本。

        【讨论】:

          【解决方案10】:

          这个问题在 webmasters stack-exchange 网站上有更好的答案here

          以上链接中也引用了更多信息,请访问httpwatch

          根据文章:

          在多种情况下 Internet Explorer 需要检查缓存条目是否有效:

          • 缓存的条目没有过期日期,并且是在浏览器会话中首次访问内容
          • 缓存条目有过期日期,但已过期
          • 用户已通过单击刷新按钮或按 F5 请求页面更新

            在此处输入代码

          【讨论】:

            猜你喜欢
            • 2018-05-05
            • 2014-05-10
            • 1970-01-01
            • 1970-01-01
            • 2023-04-02
            • 2016-02-25
            • 1970-01-01
            • 2011-11-07
            • 1970-01-01
            相关资源
            最近更新 更多