浏览器缓存知识总结及应用分析
浏览器缓存,即客户端缓存,不仅是网页性能优化中优化静态资源的绝佳工具,也是无数web开发人员在工作过程中不可避免的难题。所以我们在开发产品的时候总是尽量避免缓存的产生,在发布产品的时候我们希望通过管理缓存来提高网页的访问速度。了解浏览器缓存命中的原理是开发web应用程序的基础。本文围绕这一点,研究了浏览器缓存的相关知识,总结了缓存避免和缓存管理的方法,并结合具体场景说明了缓存的相关问题。我希望它能帮助有需要的人。
1.对浏览器缓存的基本理解
可分为强缓存和协商缓存:1)加载资源时,浏览器首先根据资源的某个http头判断是否命中强缓存。如果强缓存命中,浏览器会直接从自己的缓存中读取资源,而不会向服务器发送请求。比如对于一个css文件,如果浏览器在加载所在网页时命中强缓存,浏览器会直接从缓存中加载css,甚至不会将请求发送到网页所在的服务器;
2)当强缓存未命中时,浏览器会向服务器发送请求,服务器会根据资源的其他http头验证资源是否命中协商缓存。如果协商缓存命中,服务器会返回请求,但不会返回资源的数据,而是告诉客户端可以直接从缓存加载资源,这样浏览器会再次从自己的缓存加载资源;
3)强缓存和协商缓存有一个共同点:如果命中,都是从客户端缓存加载资源,而不是从服务器加载资源数据;不同之处在于,强缓存不会向服务器发送请求,但协商缓存会。
4)当协商缓存也未命中时,浏览器直接从服务器加载资源数据。
2.强缓存的原理
当浏览器对资源的请求到达强缓存时,返回的http状态为200,大小将在chrome developer工具的网络中显示为来自缓存。比如JD.COM首页就有很多配置了强缓存的静态资源。用chrome打开几次,然后用f12检查网络。您可以看到许多请求都是从缓存中加载的:
强缓存是通过使用两个http响应头,Expires或Cache-Control来实现的,这两个响应头用于指示客户端缓存的资源的有效期。
Expires是一个用于指示http1.0提出的资源到期时间的头,它描述了一个绝对时间,由服务器返回,用GMT格式字符串表示,如expires : thu,31dec2037 2:55:55 GMT。它的缓存原则是:
1)浏览器第一次向服务器请求资源。当服务器返回此资源时,它会在响应的标头中添加一个Expires标头,例如:
2)浏览器收到该资源后,会将该资源与所有响应头一起缓存(因此缓存命中请求返回的头不是来自服务器,而是来自之前缓存的头);
3)当浏览器再次请求该资源时,它首先从缓存中进行搜索。找到该资源后,它会取出其过期时间,并将其与当前请求时间进行比较。如果请求时间在Expires指定的时间之前,它将命中缓存,否则将不起作用。
4)如果缓存未命中,浏览器直接从服务器加载资源,重新加载时将更新Expires Header。
Expires是强缓存管理的旧标头。因为是服务器返回的绝对时间,当服务器时间和客户端时间相差较大时,缓存管理容易出现问题。例如,随意修改客户端时间会影响缓存命中的结果。因此,在http1.1中,提出了一个新的头,Cache-Control,这是一个相对时间。配置缓存时,以秒为单位表示,例如cache-control : max-age=315360000,其缓存原则为:
1)浏览器第一次向服务器请求资源。当服务器返回此资源时,它会将缓存控制的标头添加到响应的标头中,例如:
2)浏览器收到该资源后,会将该资源与所有响应头一起缓存;
3)当浏览器再次请求该资源时,它首先从缓存中进行搜索。找到该资源后,它根据其第一次请求时间和缓存控制设置的有效期计算资源到期时间,然后将该到期时间与当前请求时间进行比较。如果请求时间在到期时间之前,它将命中缓存,否则它将不起作用。
4)如果缓存未命中,浏览器直接从服务器加载资源,重新加载时将更新缓存控制头。
缓存控制描述了一个相对时间。当缓存命中时,是通过客户端时间来判断的,因此与Expires相比,Cache-Control的缓存管理更加有效和安全。
只能启用这两个标题中的一个,或者同时启用它们。当响应头中存在过期和缓存控制时,缓存控制的优先级高于过期:
3.强缓存的管理
强缓存的原理前面已经介绍过了。在实际应用中,我们会遇到需要强缓存的场景和不需要强缓存的场景。通常有两种方法来设置是否启用强缓存:
1)添加过期和缓存控制头;web服务器通过代码返回的响应;
2)通过配置web服务器,让web服务器在响应资源时统一添加Expires和Cache-Control Header。
例如,在javaweb中,我们可以使用以下代码来设置强缓存:
Java . util . date=new Java . util . date();response . setdateheader(' Expires ',date . gettime()(20000);//Expires:过期时间限制响应。setheader ('cache-control ',' public ');//缓存-控制页面是否被缓存。public:浏览器和缓存服务器都可以缓存页面信息。response.setHeader('Pragma ',' Pragma ');//Pragma:设置页面是否缓存,如果是Pragma,会缓存,但不缓存。您也可以通过java代码设置强缓存,如下所示:response。setheader ('pragma ','无缓存');response . setdateheader(' Expires ',0);response.addHeader('缓存控制','无缓存');//浏览器和缓存服务器都不应该缓存页面信息。tomcat还提供了一个ExpiresFilter来配置强缓存。具体用法请参考tomcat官方文档:
http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html
作为专业的web服务器,nginx和apache都有专门的配置文件,可以配置过期和缓存控制。如果你对运维感兴趣,可以在百度搜索“nginx set expires cache-control”或者“Apache set expires cache-control”,找到很多相关文章。
由于开发时不会专门配置强缓存,浏览器默认会缓存图片、css、js等静态资源,由于强缓存导致资源没有及时更新,所以在开发环境中看不到最新的效果。解决这个问题的方法有很多,其中常用的有以下几种:
1)直接ctrl f5,可以解决页面直接引用的资源更新问题;
2)使用浏览器的隐私模式开发;
3)如果使用chrome,f12可以禁用网络上的缓存(这是非常有效的方法):
4)在开发阶段,给资源添加一个动态参数,比如css/index.css?V=0.0001,因为每次资源修改都需要同时更新引用位置和修改参数值,操作起来不是很方便,除非在jsp这样的动态页面中开发,可以使用服务器变量来解决(v=${sysRnd}),或者可以使用一些前端构建工具来处理这个参数修改问题;
5)如果资源引用的页面嵌入在iframe中,可以在iframe区域右键点击重新加载页面,以chrome为例:
6)如果ajax请求中出现缓存问题,最有效的解决方案是在ajax请求地址中追加随机数;
7)另一种情况,iframe的src动态设置时,由于缓存问题,可能看不到最新的效果。此时,在待设置的src后添加随机数也可以解决问题;
8)如果使用grunt、have等前端工具,通过它们的grunt-contrib-connect-Connect等插件来启动一个静态服务器,那么在开发阶段就不用担心资源更新了,因为在这个静态服务器下所有资源返回的respone头中,cache-control总是设置为not cache:
4.强缓存的应用
强缓存是前端性能优化最强大的工具。没有人。对于具有大量静态资源的网页,必须使用强缓存来提高响应速度。一般来说,所有这些静态资源都配置了一个长超时的Expires或Cache-Control,这样当用户访问一个网页时,他们只会在第一次加载时向服务器请求静态资源,而在其他时候,只要缓存没有过期,用户没有强制刷新,他们就会从自己的缓存加载。例如,前面提到的JD.COM首页缓存的资源的缓存过期时间设置为2026:
但是,这种缓存配置会带来一个新的问题,那就是发布时的资源更新。例如,当用户访问第一个版本时,某个图片已经缓存在用户的计算机上。当网站发布新版本并替换此图片时,由于缓存设置,访问过第一个版本的用户默认不会请求服务器的最新图片资源,除非清除或禁用缓存或强制刷新,否则不会看到最新的图片效果。
这个问题已经有了成熟的解决方案,具体内容可以在知乎的这篇文章中详细阅读:
http://www.zhihu.com/question/20790576
文中提到的所有东西都属于理论上的解决方案,但实际上有很多前端工具可以解决这个问题。由于每个工具都涉及到很多细节,本文没有办法深入介绍。如果你感兴趣的话,可以了解一下grunt gulp webpack fis和edp,可以解决这个问题。特别是fis和edp是百度推出的前端开发平台,有现成的文档可以参考:
http://fis.baidu.com/fis3/api/index.html
http://ecomfe.github.io/edp/doc/initialization/install/
还有一点需要注意的是,强缓存通常用于静态资源,动态资源需要谨慎使用。除了服务器页面,引用静态资源的html也可以看作动态资源。如果这样的html也被缓存了,那么可能就没有机制来通知浏览器这些html在更新之后会被更新,尤其是在前端和后端分离的应用程序中。页面是纯html页面,每个访问地址可能是一个直接访问的html页面。这些页面通常不会加强缓存,以确保浏览器在访问这些页面时总是请求服务器的最新资源。
5.协商缓存的原理
当浏览器对资源的请求未命中强缓存时,它将向服务器发送请求,以验证协商缓存是否命中。如果协商缓存命中,请求响应返回的http状态将是304,并且将显示“未修改”字符串。例如,如果您打开JD.COM的主页,按f12打开开发人员工具,然后按f5刷新页面并检查网络,您可以看到许多请求命中了协商缓存:
查看单个请求的响应头,还可以看到状态代码304和字符串“未修改”。只要看到这一点,就可以表明该资源命中了协商缓存,然后是从客户端缓存加载的,而不是服务器的最新资源:
协商缓存由两对标头管理:[上次修改,如果修改-自]和[ETag,如果不匹配]。
[上次修改,如果修改-自]控制缓存的原理是:
1)浏览器第一次向服务器请求资源。当服务器返回这个资源时,它将最后修改的头添加到响应的头中。此标头指示服务器上此资源的上次修改时间:
2)当浏览器再次从服务器请求该资源时,将If-Modified-before的头添加到请求的头中,该头的值是上次请求返回的上次修改值:
3)当服务器再次收到资源请求时,根据浏览器发送If-Modified-before和资源在服务器上的上次修改时间,判断资源是否发生了变化,如果没有,则返回304 Not Modified,但不返回资源内容;如果有任何更改,资源内容将正常返回。当服务器返回304未修改响应时,上次修改的头将不会添加到响应头中,因为资源没有更改,上次修改的头也不会更改。这是当服务器返回304:
4)浏览器收到304的响应后,会从缓存加载资源。
5)如果协商缓存未命中,浏览器直接从服务器加载资源时,重新加载时会更新上次修改的Header,如果修改自会启用下次请求时上次返回的上次修改值。
[上次修改,如果修改-自]是根据服务器时间返回的标题。一般来说,这两个头一起管理协商缓存是非常可靠的,不需要调整服务器时间和篡改客户端缓存。但是,有时候服务器上的资源实际上发生了变化,但是最后一次修改的时间并没有变化,这个问题不容易定位。当这种情况发生时,它将影响协商缓存。因此,还有另一对头来管理协商缓存,即[ETag,If-None-Match]。它们的缓存管理方法是:
1)浏览器第一次向服务器请求资源。当服务器返回这个资源时,它会将ETag的头添加到respone的头中。该报头是由服务器根据当前请求的资源生成的唯一标识符。这个唯一标识符是一个字符串,只要资源发生变化就不同,与上次修改时间无关,所以可以很好地补充上次修改的问题:
2)当浏览器再次向服务器请求该资源时,在请求的头部添加If-None-Match的头部,该头部的值为上一次请求中返回的ETag的值:
3)当服务器再次收到资源请求时,根据浏览器发送If-None-Match再根据资源生成新的ETag,如果两个值相同,则表示资源没有变化,否则为变化;如果没有变化,返回304未修改,但不会返回资源内容;如果有任何更改,资源内容将正常返回。与上次修改不同,当服务器返回304未修改响应时,因为ETag已经重新生成,所以该ETag也将在响应头中返回,即使该ETag与前一个ETag没有变化:
4)浏览器收到304的响应后,会从缓存加载资源。
6.协商缓存的管理
协商缓存不同于强缓存。强缓存不向服务器发送请求,所以有时候浏览器不知道资源是否更新,但是协商缓存向服务器发送请求,所以服务器必须知道资源是否更新。大多数网络服务器默认打开协商缓存,同时启用[上次修改,如果修改-自]和[ETag,如果-不匹配],如apache:
如果没有协商缓存,那么对服务器的每一个请求都必须返回资源内容,这样服务器的性能就会极差。
【上次修改,如果修改-自】和【ETag,如果-不匹配】一般同时启用,是为了应对上次修改不可靠的情况。有一种情况需要注意:
分布式系统中多台机器之间的Last-Modified文件必须一致,以避免对不同机器进行负载均衡导致的比较失败;
分布式系统尝试关闭ETag(每台机器产生的ETag会不一样);
在JD.COM页面的资源请求中,返回的请求头只是最后修改的,没有ETag:
协商缓存需要与强缓存一起使用。在上一个截图中,除了上次修改的头之外,还有与强缓存相关的头,因为如果没有启用强缓存,协商缓存根本没有意义。
7.浏览器行为对缓存的影响
如果资源已经被浏览器缓存,在缓存失败之前,再次请求时,会先检查是否命中强缓存,如果命中,会直接读取缓存,如果没有命中,会向服务器发送请求,检查是否命中协商缓存,如果命中,会告诉浏览器仍然可以从缓存读取,否则会从服务器返回最新的资源。这是默认的处理方法,可能会因浏览器的行为而改变:
1)当ctrl f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存;
2)当f5刷新网页时,会跳过强缓存,但会检查协商缓存。
版权声明:浏览器缓存知识总结及应用分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。