@xudongh
2017-10-15T17:11:06.000000Z
字数 3569
阅读 1625
HTTP
前端开发
HTTP
浏览器缓存,也就是客户端缓存,是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。
浏览器缓存既是网页性能优化里面静态资源相关优化的一大利器,也是无数web开发人员在工作过程不可避免的一大问题,所以在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度。因此,了解缓存与控制缓存就显得非常重要了。
浏览器缓存分为两种,分别为强缓存(也称本地缓存)和协商缓存(也称弱缓存)。
对于强缓存和协商缓存,判定过程如下:
1. 浏览器加载资源时,先根据response
的header
中某些字段判断是否命中强缓存,若命中,浏览器直接从缓存中读取资源,不会发送请求到服务器。
2. 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,此时服务器根据resquest
的header
中某些字段判断是否命中协商缓存,若命中,服务器返回请求,但不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源。
对于强缓存和协商缓存,共同点在于,若命中,它们都是从客户端缓存中加载资源,而不是从服务器加载资源数据;而不同点在于,强缓存不发请求到服务器,协商缓存会发请求到服务器以咨询缓存是否过期。
普通刷新会启用协商缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,这也是为什么有时候我们更新一张图片、一个js文件,页面内容依然是旧的,但是直接浏览器访问那个图片或文件,看到的内容却是新的。
当浏览器第一次发送请求时,本地无缓存,向web服务器发送请求,服务器起端响应请求,浏览器端缓存。
在第一次请求时,服务器会将页面最后修改时间通过Last-Modified标识由服务器发送给客户端,客户端记录修改时间;服务器还会生成一个Etag,并发送给客户端。
当浏览器再次发送请求时:
根据上图,浏览器在第一次请求发生后,再次发送请求时:
response
的header
信息,然后根据header
中的Cache-Control
和Expires
来判断是否过期。若没过期则直接从缓存中获取资源信息,包括缓存的header
的信息,所以此次请求不会与服务器进行通信。这里判断是否过期,则是强缓存相关。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之前,那么本地缓存始终有效,则在缓存中读取数据。因此这种方式有一个明显的缺点,由于失效的时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。
如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。
cache-control:max-age=691200
expires:Fri, 14 Apr 2017 10:47:02 GMT
那么表示资源可以被缓存的最长时间为691200秒,会优先考虑max-age。
Cache-Control
是在http1.1中出现的,是通用首部字段,既可用在request
和response
。可以利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600
,代表着资源的有效期是3600秒。对于response
报文,cache-control
除了该字段外,还有下面几个比较常用的设置值:
简而言之,协商缓存就是想服务器发送请求以咨询本地缓存是否可用。
协商缓存主要涉及两组header
字段:Etag
和If-None-Match
、Last-Modified
和If-Modified-Since
。
If-None-Match
是requset
报文的header
中的一个字段,形如if-xxx
这种样式的请求首部字段,都可称为条件请求。
Etag
是response
报文中header
中的一个字段它是一种可将资源以字符串形式做唯一标识的方式,服务器会为每一份资源分配对应的ETag值。
其执行的过程如下:
1. 当第一次发起HTTP请求时,服务器会为相应的资源返回一个ETag值。
2. 当再次发起同一个请求时,客户端会在request
的header
中带上If-None-Match
,而它的值就是Etag的值。
3. 然后服务器会比对这个客服端发送过来的Etag是否与服务器的相同:若相同,就将If-None-Match
的值设为false
,返回状态为304
,并且服务器不返回该资源的数据,客户端继续使用本地缓存,不解析服务器返回的数据;若不相同,就将If-None-Match
的值设为true
,返回状态为200,同时服务器返回该资源的新数据,客户端重新解析服务器返回的数据。
Last-Modify
是response
报文的header
中的一个字段,其值为时间,用于标识该资源的最后修改时间。
If-Modify-Since
是request
报文的header
中的一个字段,其值也为时间。
其执行过程如下:
1. 当第一次发起HTTP请求时,服务器response
的header
中包含Last-Modify
,标明该资源的最后修改时间,如:
Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。
requset
的header
中包含If-Modify-Since
字段,该值为缓存之前服务器返回的Last-Modify
的值,服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。Last-Modified与Etag类似。不过Last-Modified表示响应资源在服务器最后修改时间而已。与Etag相比,不足为:
而且,Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。
另外,Last-Modified与ETag是可以一起使用的,·服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。