浏览器缓存是性能优化的重要一环,对于前端的重要性不言而喻。之前一直略知一二,所以这次整理总结一下。1、缓存机制首先我们对其匹配过程有个大概的认识,如下:浏览器在发送请求之前,根据expires和cache-control判断是否命中(包括是否过期)强缓存策略请求标头。如果命中,则直接从缓存中获取资源,而不发送请求。如果没有命中,则进行下一步。如果没有命中强缓存规则,浏览器会发送请求,根据请求头的last-modified和etag判断是否命中协商缓存。如果命中,则直接从缓存中获取资源。如果没有命中,则进行下一步。如果前面两步都没有命中,则直接从服务器获取资源。2、强缓存强缓存:不会向服务器发送请求,而是直接从缓存中读取资源。2.1强缓存原理强制缓存就是在浏览器缓存中查找请求结果,根据结果的缓存规则决定是否使用缓存结果的过程。强制缓存主要有三种情况(暂不分析协商缓存过程),如下:第一个请求,没有缓存结果和缓存ID,直接向服务器发送请求。有一个缓存ID和缓存结果,但它们已过期。如果是强制缓存,则使用协商缓存(暂不分析)。缓存的结果和CacheID,且结果没有过期,强制缓存生效,直接返回结果。那么强制缓存的缓存规则是什么呢?当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中,连同请求结果一起返回给浏览器。控制强制缓存的字段有Expires和Cache-Control,其中Cache-ControlPriority高于Expires。2.1.1、Expires缓存过期时间用于指定资源过期的时间,是服务器端的具体时间点。也就是说,Expires=max-age+请求时间需要和Last-modified结合使用。Expires是Web服务器的响应头字段。在响应http请求时,告诉浏览器在过期时间之前,浏览器可以直接从浏览器缓存中取数据,不需要再次请求。Expires是HTTP/1的产物,受本地时间限制。如果本地时间被修改,缓存可能会失效。2.1.2、Cache-Control在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存。主要取值有:public:所有内容都会被缓存(客户端和代理服务器都可以缓存)private:所有内容只能被客户端缓存。Cache-Control的默认值为no-cache:客户端缓存内容,但是否使用缓存需要通过协商缓存来验证。no-store:所有内容都不会缓存,即不使用强制缓存,也不使用协商缓存max-age=xxx(xxx为数字):缓存的内容会在xxx秒后过期。需要注意的是,no-cache这个名字有点误导。设置no-cache后,并不代表浏览器不再缓存数据,而是浏览器在使用缓存数据时,需要确认数据是否仍然与服务器保持一致,即协商缓存.而no-store就是不缓存,即既不使用强制缓存也不使用协商缓存。2.1.3.设置强缓存需要服务器设置expires和cache-control。nginx代码参考,设置一年缓存时间:location~.*\.(ico|svg|ttf|eot|woff)(.*){proxy_cachepnc;proxy_cache_valid2003041y;proxy_cache_validany1m;proxy_cache_lockon;proxy_cache_lock_timeout5s;proxy_cache_use_staleupdatingerrortimeoutinvalid_http20}其中http510是浏览器的缓存存储,如何判断强制缓存在浏览器中是否生效?这就是我们下面要说的fromdiskcache和frommemorycache。2.2、fromdiskcache和frommemorycache细心的同学应该注意到,Chrome的网络请求大小在开发的时候会出现三种情况:fromdiskcache(磁盘缓存),from内存缓存(memorycache),资源大小值。状态类型描述200formmemorycache不请求网络资源,资源在内存中,一般脚本、字体、图片会存储在内存中200formdiskceche不请求网络资源,在磁盘中,一般非脚本会存储在内存中,比如css等待200resourcesizevalue从服务器下载最新的资源304messagesizerequest服务器发现资源没有更新,使用本地资源浏览器读取缓存的顺序是内存->磁盘。以https://github.com/xiangxingchen/blog为例。当我们第一次访问https://github.com/xiangxingchen/blog时,我们关闭tab,然后打开https://github.com/xiangxingchen/blog3.协商缓存协商缓存是指在缓存之后强制失败,浏览器向服务器发送带有缓存标识的请求,服务器根据缓存标识决定是否使用缓存。主要有两种情况:Negotiation缓存有效,返回304和NotModifiedNegotiation缓存失效,返回200和请求结果3.1,Last-Modified和If-Modified-Since浏览器先发送请求让服务器返回last响应头中请求资源的更新时间为last-modified,浏览器会缓存这个时间。然后在浏览器的下一次请求中,请求头中包含if-modified-since:[savedlast-modifiedvalue]。比较浏览器发送的修改时间和服务器的修改时间。如果一致,说明资源没有变化。服务器返回一个空文本的响应,允许浏览器从缓存中读取资源,这大大减少了请求时间。消耗。由于last-modified依赖的是保存的绝对时间,所以还是会出现错误:保存的时间是以秒为单位,1秒内的多次修改是抓不到的;每台机器读取的时间不一致,有可能出错。为了改善这个问题,建议使用etag。3.2.ETag和If-None-Matchetag是http协议提供的几种机制之一,一种Web缓存校验机制,允许客户端进行缓存协商。生成etag的常见方法包括对资源内容使用抗冲突散列函数、使用最后修改时间戳的散列,甚至只是版本号。与上次修改的相同。浏览器会先发送请求获取etag的值,然后在下一次请求的请求头中带上if-none-match:[etag的保存值]。将发送的etag值与服务器重新生成的etag值进行比较。如果一致,说明资源没有变化,服务器返回一个空文本的响应,告诉浏览器从缓存中读取资源。etag可以解决last-modified的一些缺点,但是etag每次生成server都需要进行读写操作,而last-modified只需要读操作。从这个角度来说,etag消耗的更多。两者比较在准确率方面:Etag优于Last-Modified。Priority:服务器验证优先Etag。性能方面:Etag不如Last-Modified4。用户行为对浏览器缓存的影响打开网页,在地址栏输入地址:查找磁盘缓存中是否有匹配项。可用时使用;如果没有,发送网络请求。正常刷新(F5):因为TAB没有关闭,所以内存缓存可用,会优先使用(如果匹配)。第二个是磁盘缓存。强制刷新(Ctrl+F5):浏览器不使用缓存,所以发送的请求头都有Cache-control:no-cache(为了兼容,Pragma:no-cache也包括在内),服务端直接返回200以及最新内容。5、总结中,如有错误或不严谨的地方,请务必指正,万分感谢。如果你喜欢或启发了什么,欢迎star也是对作者的一种鼓励。
