一定要知道的浏览器缓存知识
标签(空格分隔): web浏览器缓存
为什么要写一篇这样的文章呢?那就是被缓存坑了,既然坑了就要刨根问题找到问题所在并解决它,所以这篇文章的目的就是为了纪念一下。
什么破问题呢?
浏览器为了增强用户体验会对页面(html)及页面中的(img,js,css)资源进行缓存,微信浏览器尤其严重,资源文件我们通过webpack等打包工具实现了缓存的控制,通过hash修改文件名,是没有问题的,关键在于对html文件的缓存,html文件都被缓存了,资源不缓存有个撒用,有个撒用?
一些的解决方案
1、设置meta标签(部分浏览器有效,对于微信这样的奇葩,根本没用。)
|
|
2、在html后面加上?v=20170705这样的hash值,需要更改放出去的链接,不太现实。在首次访问页面时中自动生成hash值改变url,显然是不明智的,导致微信浏览器缓存了很多份入口文件,想想我们更新版本的次数就知道,有多少次版本更新就有多少个文件缓存在用户的浏览器中。
3、给index.html的跟标签html加上一个不存在的manifest文件
|
|
这个是w3c的明确表述的,第一句就说了,如果manifest文件不存在,浏览器对此页面的缓存将会失效。但是,对于微信浏览器来说,没用的。(没有具体测试过,网上有人实践过没有)
问题根源服务器配置的问题
查看页面的请求头,第一次请求html为200,以后每次都是304刷新,继续查看请求头,发现服务器返回的头部中包含ETag和last-modify这两个参数,服务器利用这两个参数对html进行缓存控制,所以只要服务器进行处理,对请求的数据进行处理就可以了,不在缓存html文件,每次返回200即可。但是我们后端同事对缓存这些并不是很了解,推动他们修改,要告诉他们缘由,所以我觉得有必要更深入了解关于缓存的问题。下面会介绍一下缓存的基本概念。
闲扯结束,进入正题。
缓存
缓存分为服务端侧(server side,比如 Nginx、Apache)和客户端侧(client side,比如 web browser)。
常用的服务端缓存有CDN缓存,客户端缓存就是指浏览器缓存。
浏览器缓存
浏览器缓存分为强缓存和协商缓存:
1 强缓存:浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;
2 协商缓存:当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回(304),但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;若未命中请求,则将资源返回客户端,并更新本地缓存数据(200)。
区别 : 强缓存不发请求到服务器,协商缓存会发请求到服务器。
如何设置缓存
1 HTML Meta标签控制缓存(非HTTP协议定义)
|
|
上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。这种方法使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。
2 HTTP头信息控制缓存
HTTP头信息控制缓存是通过Expires(强缓存)、Cache-control(强缓存)、Last-Modified/If-Modified-Since(协商缓存)、Etag/If-None-Match(协商缓存)实现,下面详细介绍。
1)、Expires:是http1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2016 23:55:55 GMT,
读取缓存数据条件:缓存过期时间(服务器的)< 当前时间(客户端的
缺点: Expires是较老的强缓存管理header,由于它是服务器返回的一个绝对时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。
2)、Cache-Control:描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较Expires,Cache-Control的缓存管理更有效,安全一些。
读取缓存数据条件:上次缓存时间(客户端的)+max-age < 当前时间(客户端的)
Cache-Control值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
Public指示响应可被任何缓存区缓存。
Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当前用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache指示请求或响应消息不能缓存,该选项并不是说可以设置”不缓存“,而是需要和服务器确认
no-store在请求消息中发送将使得请求和响应消息都不使用缓存,完全不存下來。
max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。上次缓存时间(客户端的)+max-age(64200s)<客户端当前时间
min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。
注意: 这两个header可以只启用一个,也可以同时启用,当response header中,Expires和Cache-Control同时存在时,Cache-Control优先级高于Expires:
3)、Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。
Last-Modified: 标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
If-Modified-Since: 当资源过期时(强缓存失效),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
缺点
Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间(无法及时更新文件)
如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存,有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形(无法使用缓存)。
4)、Etag/If-None-Match:
Etag/If-None-Match也要配合Cache-Control使用。
Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag一起使用时,服务器会优先验证ETag。
参考文章:
1、 浏览器 HTTP 协议缓存机制详解
2、 详解web缓存