浏览器缓存是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就能够直接从本地磁盘加载文档。html
因此根据上面的特色,浏览器缓存有下面的优势:web
减小冗余的数据传输浏览器
减小服务器负担缓存
加快客户端加载网页的速度性能优化
浏览器缓存是Web性能优化的重要方式。那么浏览器缓存的过程到底是怎么样的呢?服务器
在浏览器第一次发起请求时,本地无缓存,向web服务器发送请求,服务器起端响应请求,浏览器端缓存。过程以下:并发
在第一次请求时,服务器会将页面最后修改时间经过Last-Modified
标识由服务器发送给客户端,客户端记录修改时间;服务器还会生成一个Etag,并发送给客户端。性能
浏览器后续再次进行请求时:学习
浏览器缓存主要分为强强缓存(也称本地缓存)和协商缓存(也称弱缓存)。根据上图,浏览器在第一次请求发生后,再次发送请求时:优化
浏览器请求某一资源时,会先获取该资源缓存的header信息,而后根据header中的Cache-Control
和Expires
来判断是否过时。若没过时则直接从缓存中获取资源信息,包括缓存的header的信息,因此这次请求不会与服务器进行通讯。这里判断是否过时,则是强缓存相关。后面会讲Cache-Control
和Expires
相关。
若是显示已过时,浏览器会向服务器端发送请求,这个请求会携带第一次请求返回的有关缓存的header字段信息,好比客户端会经过If-None-Match
头将先前服务器端发送过来的Etag发送给服务器,服务会对比这个客户端发过来的Etag是否与服务器的相同,若相同,就将If-None-Match
的值设为false,返回状态304,客户端继续使用本地缓存,不解析服务器端发回来的数据,若不相同就将If-None-Match
的值设为true,返回状态为200,客户端从新机械服务器端返回的数据;客户端还会经过If-Modified-Since
头将先前服务器端发过来的最后修改时间戳发送给服务器,服务器端经过这个时间戳判断客户端的页面是不是最新的,若是不是最新的,则返回最新的内容,若是是最新的,则返回304,客户端继续使用本地缓存。
强缓存是利用http头中的Expires
和Cache-Control
两个字段来控制的,用来表示资源的缓存时间。强缓存中,普通刷新会忽略它,但不会清除它,须要强制刷新。浏览器强制刷新,请求会带上Cache-Control:no-cache
和Pragma:no-cache
Expires
是http1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串。如我如今这个网页的Expires
值是:expires:Fri, 14 Apr 2017 10:47:02 GMT
。这个时间表明这这个资源的失效时间,只要发送请求时间是在Expires
以前,那么本地缓存始终有效,则在缓存中读取数据。因此这种方式有一个明显的缺点,因为失效的时间是一个绝对时间,因此当服务器与客户端时间误差较大时,就会致使缓存混乱。若是同时出现Cache-Control:max-age
和Expires
,那么max-age
优先级更高。如我主页的response headers部分以下:
cache-control:max-age=691200 expires:Fri, 14 Apr 2017 10:47:02 GMT
那么表示资源能够被缓存的最长时间为691200秒,会优先考虑max-age
。
Cache-Control是在http1.1中出现的,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,表明着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较经常使用的设置值:
no-cache:不使用本地缓存。须要使用缓存协商,先与服务器确认返回的响应是否被更改,若是以前的响应中存在ETag,那么请求的时候会与服务端验证,若是资源未被更改,则能够避免从新下载。
no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
public:能够被全部的用户缓存,包括终端用户和CDN等中间代理服务器。
private:只能被终端用户的浏览器缓存,不容许CDN等中继缓存服务器对其缓存。
Cache-Control与Expires能够在服务端配置同时启用,同时启用的时候Cache-Control优先级高。
协商缓存就是由服务器来肯定缓存资源是否可用,因此客户端与服务器端要经过某种标识来进行通讯,从而让服务器判断请求资源是否能够缓存访问。
普通刷新会启用弱缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、经过连接引用资源等状况下,浏览器才会启用强缓存,这也是为何有时候咱们更新一张图片、一个js文件,页面内容依然是旧的,可是直接浏览器访问那个图片或文件,看到的内容倒是新的。
这个主要涉及到两组header字段:Etag
和If-None-Match
、Last-Modified
和If-Modified-Since
。上面以及说得很清楚这两组怎么使用啦~复习一下:
Etag
和If-None-Match
Etag/If-None-Match返回的是一个校验码。ETag能够保证每个资源是惟一的,资源变化都会致使ETag变化。服务器根据浏览器上送的If-None-Match值来判断是否命中缓存。
与Last-Modified不同的是,当服务器返回304 Not Modified的响应时,因为ETag从新生成过,response header中还会把这个ETag返回,即便这个ETag跟以前的没有变化。
浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存以前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。
若是命中缓存,则返回304,而且不会返回资源内容,而且不会返回Last-Modify。
你可能会以为使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为何还须要Etag呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:
一些文件也许会周期性的更改,可是他的内容并不改变(仅仅改变的修改时间),这个时候咱们并不但愿客户端认为这个文件被修改了,而从新GET;
某些文件修改很是频繁,好比在秒如下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改没法判断(或者说UNIX记录MTIME只能精确到秒);
某些服务器不能精确的获得文件的最后修改时间。
Last-Modified与ETag是能够一块儿使用的,服务器会优先验证ETag,一致的状况下,才会继续比对Last-Modified,最后才决定是否返回304。
另外以为一篇很好的文章,从缓存策略来学习HTTP缓存:HTTP基于缓存策略三要素分解法