停止浏览器对应该保持缓存的图像发出HTTP请求 - mod_expires

时间:2012-04-06 20:13:09

标签: caching browser http-headers mod-expires

在这里阅读了很多文章和一些问题之后,我终于成功激活了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&gt; Net&gt;图像)我可以看到不同的缓存行为(我显然开始使用浏览器缓存完全空,我使用“清除所有历史记录”强制在浏览器上删除缓存) :

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

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

  • 当我关闭浏览器并在同一页面上再次打开它时,愚蠢的浏览器无论如何都会向每台图像的服务器发出一次HTTP请求:它不会使图像下载,但它仍会生成HTTP请求,就像浏览器向服务器查询图像(服务器回复200 OK)。 这是令我恼火的人!

如果您有兴趣,我也会附上以下图表:

enter image description here

enter image description here

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

EDIT2:并按照建议的here移除Last-Modified标题,但无法解决问题,它没有任何区别。

10 个答案:

答案 0 :(得分:28)

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

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

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

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

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

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

但是如果你看一下html5附带的其他可用的客户端解决方案,还有一个阻止资源加载的范围

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

答案 1 :(得分:14)

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

我建议使用真正有用的Firefox插件 Live HTTP标头,这样您就可以看到网络上的实际情况。

而且可以肯定的是,你可以ssh / putty你的服务器并执行类似

的操作
tail -f /var/log/apache2/access.log

答案 2 :(得分:12)

“重新加载”和“刷新”之间存在差异。导航到具有后退和前进按钮的页面通常不会发起新的HTTP请求,但是专门按F5“刷新”页面将导致浏览器仔细检查其缓存。这取决于浏览器,但似乎是FF和Chrome的标准(即能够轻松查看其网络流量的浏览器。)点击F6,输入应该关注URL地址栏然后“转到”它,这应该重新加载页面,但不要仔细检查页面上的资产。

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

如果你在开发者网络面板中看到(200 OK BFCache),那么服务器从未被命中 - 甚至要求if-modified-since。

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

答案 3 :(得分:7)

如果我使用F5或F5 + Ctrl强制刷新,则发送请求。但是,如果我关闭浏览器并再次输入url,则会发送NO reqeust。我测试是否发送请求的方式是在服务器上的开始请求中使用断点,即使请求未发送,它仍然在Firebug中显示为已经完成7毫秒等待,所以要小心这一点。

答案 4 :(得分:6)

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

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

答案 5 :(得分:4)

在我花了相当多的时间寻找合理的答案后,我发现以下链接最有用,它确实回答了这里提出的问题。

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

答案 6 :(得分:0)

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

首次使用HTML5 本地存储缓存图片。

  • [+] 您可以阻止浏览器发送HTTP请求,无论用户多么努力(F5,ctrl + F5,99%)都会返回304(未修改)只是重新访问页面等。)

  • [ - ] 您必须在javascript支持方面加倍努力。

  • [ - ] 图像存储在base64中(我们无法存储二进制数据),这就是为什么每次在客户端解码它们的原因。哪个通常非常快,而且不是什么大问题,但它仍然是客户端的一些额外的CPU使用,应该牢记。

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

  • [?] 支持多数浏览器。 http://caniuse.com/#search=localstorage

Example

Test

答案 7 :(得分:0)

您在Chrome中看到的并不是实际HTTP请求的记录 - 它是资产请求的记录。 Chrome会执行此操作以向您显示页面实际上正在请求资产。但是,此视图实际上并不真正表明是否正在进行请求。如果资产已缓存,Chrome将永远不会实际创建基础HTTP请求。

您也可以将鼠标悬停在时间轴中的紫色片段上进行确认。缓存资源在工具提示中将有(from cache)

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

实际上,要验证请求实际上并未实现,您需要检查服务器日志或使用Charles或Fiddler之类的调试代理。这将在HTTP级别上工作,以确保请求实际上不会发生。

答案 8 :(得分:0)

缓存验证和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并提供修改后的资源版本。

答案 9 :(得分:0)

此问题在网站管理员堆栈交换网站上有更好的答案here

以上链接中引用的更多信息位于httpwatch

根据文章:

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

  • 缓存条目没有到期日期,并且首次在浏览器会话中访问内容
  • 缓存条目的截止日期已过期
  • 用户通过单击“刷新”按钮或按F5

    请求页面更新

    在此输入代码