停止浏览器为应保持caching的图像发出HTTP请求 – mod_expires

在阅读了许多文章和这里的一些问题之后, 我终于成功地激活了Apache mod_expires ,告诉浏览器它必须caching图像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年。 但部分原因: 如果closures并重新打开浏览器,浏览器不再从服务器下载图像但浏览器仍然向服务器询问每个图像的HTTP请求

如何强制浏览器停止对每个图像的HTTP请求? 即使这些HTTP请求没有被下载的图像后,他们仍然对服务器的请求进行连接 icrease延迟和减慢页面渲染!

我已经告诉浏览器它必须保持图像caching1年! 为什么浏览器仍然询问每个图像的服务器(即使它不下载图像)?


查看FireBug中的networking图(菜单FireBug的>网>图像)我可以看到不同的caching行为(我明显开始浏览器caching完全是空的,我强迫删除浏览器使用“清除所有历史logging”)caching:

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

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

  • 当我closures浏览器并在同一页面上再次打开浏览器时,愚蠢的浏览器无论如何都会向服务器发送一次每个图像的HTTP请求:它不会下载图像,但仍会发出HTTP请求,就像浏览器查询服务器关于图像 (服务器答复200 OK)。 这是刺激我的人!

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

在这里输入图像说明

在这里输入图像说明

编辑:只是testing现在还与FireFox 11.0只是为了确保它不是我的FireFox 3.6太旧的问题。 同样的事情发生! 我也testing了Google站点和Stackoverflow站点 ,它们都发送Cache-Control: max-age=...但是浏览器仍然会在浏览器closures后再向服务器发送HTTP请求页面 ,服务器响应后浏览器不下载图像(正如我上面解释),但它仍然使该死的请求,增加时间看页面。

编辑2:并删除Last-Modified标题如这里build议,不解决问题,它没有任何区别。

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

我build议使用真正有用的Firefox插件Live HTTP标头,以便您可以查看networking上发生了什么。

而且可以肯定的是,你可以ssh / putty你的服务器并且做类似的事情

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

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

所有现代浏览器都会向显示的每个页面元素发送HTTP请求,而不考虑caching状态。 这是根据Web服务(尤其是广告networking)的要求做出的devise决定,以确保HTTP服务器能够维护每个元素的每个显示的logging。

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

于是达成休战:浏览器总是发送HTTP请求,即使是未过期的caching元素。 服务器将响应HTTP 304状态码(“未修改”)。 这允许服务器logging图像被显示给客户的事实。 结果,广告networking通常停止使用随机化的图像名称来绕过networkingcaching服务器。

这给了广告networking他们想要的东西 – logging每个图像显示 – 它给了ISP他们想要的 – caching图像和静态内容。

这就是为什么阻止浏览器发送caching页面元素的HTTP请求的原因。

但是,如果你看看html5附带的其他可用的客户端解决scheme,有一个范围可以防止资源加载

  1. Cache Manifest (尽pipe有其陷阱)
  2. IndexedDB (很好的asynchronousfunction,允许blob存储)
  3. 本地存储 (不是asynchronous)

“重新装载”和“刷新”是有区别的。 使用后退和前进button导航到页面通常不会启动新的HTTP请求,但是特别是按F5来“刷新”页面将导致浏览器再次检查其caching。 这是依赖于浏览器,但似乎是FF和Chrome(即有能力轻松观看他们的networkingstream量的浏览器)的常态。点击F6,input应该集中URL地址栏,然后“去”,应该重新加载页面,但不检查页面上的资产。

更新 :澄清后退和前进的导航行为。 它在浏览器中被称为“Back Forward Cache”或BFCache 。 当您使用后退/前进button进行导航时,目的是向您显示您在自己的时间线上看到的页面。 即使服务器caching标头指出特定项目已过期,也不会在使用后退和前进时发出服务器请求。

如果您在开发人员networking面板中看到(200 OK BFCache),那么服务器从未被击中 – 甚至不会询问是否修改。

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

如果我使用F5或F5 + Ctrl强制刷新,则发送一个请求。 但是,如果我closures浏览器并再次inputurl,则不需要发送。 我testing一个请求是否发送的方法是在服务器上的开始请求上使用断点,即使请求没有发送,它仍然显示在Firebug中已经做了7毫秒的等待,所以要小心这一点。

你在这里描述的并不反映我的经验。 如果内容是用no-store指令提供的,或者你做了一个明确的刷新,那么是的,我希望它会返回到原始服务器,否则它应该跨浏览器重新启动caching(假设它被允许,并且可以写一个caching文件)。

看看你的瀑布更详细一点(这是棘手的,因为他们有点小,模糊)浏览器似乎正在做它应该 – 它图像的条目 – 但这些只是从本地caching加载不是从原始服务器 – 检查响应中的“date”标题(为什么你认为这需要几毫秒而不是秒?)。 这就是为什么他们有不同的颜色。

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

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

如果这是一个生死攸关的问题(如果你想这样优化页面加载,或者如果你想减less服务器上的负载,无论如何),那么是一个解决方法。

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

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

  • [ – ]你必须在javascript支持这一点上做一些额外的努力。

  • [ – ]图像存储在base64(我们不能存储二进制数据),这就是为什么他们每次在客户端解码。 这通常是相当快的,没有什么大不了的,但是在客户端仍然是一些额外的CPU使用,应该记住。

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

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

testing

您在Chrome中看到的不是实际HTTP请求的logging – 这是资产请求的logging。 Chrome会这样做,以显示资源实际上是由页面请求的。 但是,这个观点并不真正表明是否正在提出请求。 如果资源被caching,Chrome将永远不会实际创build底层的HTTP请求。

您也可以将鼠标hover在时间线上的紫色线段上进行确认。 caching的资源将在工具提示中有(from cache)

为了看到实际的HTTP请求,你需要看一下较低的级别。 在某些浏览器中,可以使用插件(如Live HTTP Headers)来完成。

但实际上,为了validation请求并不是真的被做出来的,你需要检查你的服务器日志或者使用像Charles或Fiddler这样的debugging代理。 这将在HTTP级别上工作,以确保请求没有实际发生。

cachingvalidation和304响应

Internet Explorer需要检查caching条目是否有效的情况很多:

  • caching的条目没有到期date,并且在浏览器会话中第一次访问内容

  • caching的条目具有到期date,但已过期

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

如果caching的条目具有最后修改date,则IE将其发送到GET请求消息的If-Modified-Since标头中:

 GET http://img.dovov.comlogo.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标题并作出相应的响应。 如果自指定的date/时间起内容没有被更改,则它将回复一个状态码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从caching中读取它需要的数据。 实际上,它就像是redirect到本地浏览器caching。

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

这个问题在网站pipe理员堆栈交换站点有更好的答案。

更多信息,也在上面的链接引用, httpwatch

根据这篇文章:

Internet Explorer需要检查caching条目是否有效的情况很多:

  • caching的条目没有到期date,并且在浏览器会话中第一次访问内容
  • caching的条目具有到期date,但已过期
  • 用户通过单击刷新button或按F5请求页面更新

    在此处input代码