[关闭]
@xudongh 2017-10-15T17:11:06.000000Z 字数 3569 阅读 1625

HTTP缓存机制

HTTP 前端开发 HTTP


浏览器缓存,也就是客户端缓存,是浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。
浏览器缓存既是网页性能优化里面静态资源相关优化的一大利器,也是无数web开发人员在工作过程不可避免的一大问题,所以在产品开发的时候我们总是想办法避免缓存产生,而在产品发布之时又在想策略管理缓存提升网页的访问速度。因此,了解缓存与控制缓存就显得非常重要了。


浏览器缓存

浏览器缓存分为两种,分别为强缓存(也称本地缓存)协商缓存(也称弱缓存)

对于强缓存和协商缓存,判定过程如下:
1. 浏览器加载资源时,先根据responseheader中某些字段判断是否命中强缓存,若命中,浏览器直接从缓存中读取资源,不会发送请求到服务器。
2. 当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,此时服务器根据resquestheader中某些字段判断是否命中协商缓存,若命中,服务器返回请求,但不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源。

对于强缓存和协商缓存,共同点在于,若命中,它们都是从客户端缓存中加载资源,而不是从服务器加载资源数据;而不同点在于,强缓存不发请求到服务器,协商缓存会发请求到服务器以咨询缓存是否过期。

普通刷新会启用协商缓存,忽略强缓存。只有在地址栏或收藏夹输入网址、通过链接引用资源等情况下,浏览器才会启用强缓存,这也是为什么有时候我们更新一张图片、一个js文件,页面内容依然是旧的,但是直接浏览器访问那个图片或文件,看到的内容却是新的。


浏览器发送请求过程

当浏览器第一次发送请求时,本地无缓存,向web服务器发送请求,服务器起端响应请求,浏览器端缓存。

http首次请求

在第一次请求时,服务器会将页面最后修改时间通过Last-Modified标识由服务器发送给客户端,客户端记录修改时间;服务器还会生成一个Etag,并发送给客户端。

当浏览器再次发送请求时:
此处输入图片的描述

根据上图,浏览器在第一次请求发生后,再次发送请求时


强缓存

简而言之,强缓存就是在客户端进行验证本地缓存是否可用。
强缓存是利用http头中的ExpiresCache-Control两个字段来控制的,用来表示资源的缓存时间。
强缓存中,普通刷新会忽略它,但不会清除它;而强制刷新,请求会带上Cache-Control:no-cachePragma:no-cache

Expires

Expires是http1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串,该时间代表着这个资源的失效时间,只要发送请求时间是在Expires之前,那么本地缓存始终有效,则在缓存中读取数据。因此这种方式有一个明显的缺点,由于失效的时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。
如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。

  1. cache-control:max-age=691200
  2. expires:Fri, 14 Apr 2017 10:47:02 GMT

那么表示资源可以被缓存的最长时间为691200秒,会优先考虑max-age。

Cache-Control

Cache-Control是在http1.1中出现的,是通用首部字段,既可用在requestresponse。可以利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,代表着资源的有效期是3600秒。对于response报文,cache-control除了该字段外,还有下面几个比较常用的设置值:


协商缓存

简而言之,协商缓存就是想服务器发送请求以咨询本地缓存是否可用。
协商缓存主要涉及两组header字段:EtagIf-None-MatchLast-ModifiedIf-Modified-Since

Etag和If-None-Match

If-None-Matchrequset报文的header中的一个字段,形如if-xxx这种样式的请求首部字段,都可称为条件请求。
Etagresponse报文中header中的一个字段它是一种可将资源以字符串形式做唯一标识的方式,服务器会为每一份资源分配对应的ETag值。

其执行的过程如下:
1. 当第一次发起HTTP请求时,服务器会为相应的资源返回一个ETag值。
2. 当再次发起同一个请求时,客户端会在requestheader中带上If-None-Match,而它的值就是Etag的值。
3. 然后服务器会比对这个客服端发送过来的Etag是否与服务器的相同:若相同,就将If-None-Match的值设为false,返回状态为304,并且服务器不返回该资源的数据,客户端继续使用本地缓存,不解析服务器返回的数据;若不相同,就将If-None-Match的值设为true,返回状态为200,同时服务器返回该资源的新数据,客户端重新解析服务器返回的数据。

Last-Modify和If-Modify-Since

Last-Modifyresponse报文的header中的一个字段,其值为时间,用于标识该资源的最后修改时间。
If-Modify-Sincerequest报文的header中的一个字段,其值也为时间。

其执行过程如下:
1. 当第一次发起HTTP请求时,服务器responseheader中包含Last-Modify,标明该资源的最后修改时间,如:

  1. Last-Modify: Thu,31 Dec 2037 23:59:59 GMT
  1. 当再次发起HTTP请求时,客户端requsetheader中包含If-Modify-Since字段,该值为缓存之前服务器返回的Last-Modify的值,服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。
  2. 如果命中缓存,则返回304,并且不会返回资源内容,并且不会返回Last-Modify。

两者比较

Last-Modified与Etag类似。不过Last-Modified表示响应资源在服务器最后修改时间而已。与Etag相比,不足为:

而且,Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。

另外,Last-Modified与ETag是可以一起使用的,·服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注