为什么需要缓存?
节省资源,节省流量,节省时间,也就是所谓的优化。
怎么缓存?
缓存可以简单的划分成两种类型:强缓存(200 from cache)与协商缓存(304)
区别简述如下:
- 强缓存(200 from cache)时,浏览器如果判断本地缓存未过期,就直接使用,无需发起http请求
Expires
Cache-Control
- 协商缓存(304)时,浏览器会向服务端发起http请求,然后服务端告诉浏览器文件未改变,让浏览器使用本地缓存
Last-Modified
E-tag
以下,分别介绍。
Expires
在 HTTP Response Header 中添加 Expires 字段,表示 Cache 到期时间。
Expires: Wed, 21 Oct 2015 07:28:00 GMT
浏览器收到这个 Response 之后会把资源缓存到本地,当浏览器再次访问当前页面需要请求该资源时,浏览器会检查现在的时间是否超过 Expires 设置的时间。 如果没有超过,浏览器便不会发送请求,而是直接使用缓存的资源。
通过Chrome开发工具可查看到上图的信息,代表这个请求未发出,使用的是本地缓存。
但是 Expires 存在一个问题,浏览器检查这个 Expires 的时间用的是电脑自身的时间,而设置 Expires 时间的是服务器,所以会存在服务器与客户端两者时间不同步的情况,这会使缓存无效。
Cache-Control
Expires
是 http 1.0 就存在的缓存控制 Header ,存在上述的缺陷,所以在 http 1.1 中出了新的缓存控制 Header ,Cache-Control
。
设置缓存时间的用法是 Cache-Control: max-age=30
,这代表这个 Response 的缓存时间为 30秒,这个时间是相对于请求的时间。
提及一下,Cache-Control
的优先级比 Expires
更高,也就是说,在 Cache-Control
设定 max-age
的情况下,以 max-age
作判断依据。
当资源过期了
在 Expires
与 Cache-Control
设定的期限之前,都是不发送请求,资源都是从本地缓存中获取,当超过期限时,就会发送请求到服务器,进入一个协商缓存的判断。
唔,协商缓存可以这么理解……
- 首先,当前资源的 Header 设置的强缓存时间已到达期限。
- 所以,需要从服务器中重新获取资源。
- 那么,在这一步可以做个判断:比较之前缓存已到期的资源和将要重新获取的资源是否相同。
- 如果,得出比较结果是相同,则服务器就不发送请求资源,反之则发送请求资源。
比较资源的方法就是通过 Last-Modified
和 E-tag
。
Last-Modified
这个是 http 1.0 中就存在的方法,Last-Modified
与 If-Modified-Since
搭配使用。
在服务器发送资源时,在响应头中添加一个 Last-Modified
头部,表示这个资源上次更改的时间。当缓存过期时,浏览器发送请求,请求头中携带 If-Modified-Since
信息(资源上次更改的时间), 服务器利用这个信息来判断。
如果在这段时间,资源都不曾变更过,则服务器会回一个 Status code : 304 (Not Modified)
,表示浏览器可以继续沿用这份资源。
不过这个方法存在一个缺点,它所谓的资源变更指的是编辑时间有无变化。当你将资源点开,然后保存关闭,编辑时间就变化了,就会引起所谓的变更,但是内容却和之前没任何的不同,还是一模一样的。
所以比起判断编辑时间,以内容是否有变更作为判断依据会更方便,就有了 E-tag
。
E-tag
这个是 http 1.1 中的方法,E-tag
和 If-None-Match
搭配使用。
获取资源的 MD5 值,将该值设置给 E-tag
响应头,然后服务器将响应发送给浏览器,当缓存过期时,浏览器发送请求,请求头中携带 If-None-Match
信息(MD5 值), 服务器利用这个信息来判断。
MD5:是一种指纹机制,代表文件相关指纹,只有文件变才会变,也只要文件变就会变。
如果在这段时间,资源不曾变更过(MD5 值没变化),则服务器会回一个 Status code : 304 (Not Modified)
,表示浏览器可以继续沿用这份资源。
首页的缓存策略
对于静态资源一般都设置缓存,但一个网站首页会特殊些,因为网站首页的变动频率相较静态资源来说会更为高,而且一有变动便希望用户能立即看到变化,要到达这个目的就需要实现:缓存首页,只要首页一变动就立即更新缓存。
方法1:Cache-Control: max-age = 0
这个表示缓存在零秒后过期,浏览器访问网页时会向服务器发送请求,由 E-tag
来判断是使用缓存,还是更新缓存。
方法2:Cache-Control: no-cache
这个表示缓存资源,但浏览器访问网页时不优先使用缓存,会向服务器发送请求,由 E-tag
来判断是使用缓存,还是更新缓存。
方法2 和 方法1 几乎一样。
值得注意的是 Cache-Control: no-cache
和 Cache-Control: no-store
间的差异。
Cache-Control: no-cache
是不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
Cache-Control: no-store
是直接禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
强缓存如何重新加载缓存缓存过的资源
上面说到,使用强缓存时,浏览器不会发送请求到服务端,根据设置的缓存时间浏览器一直从缓存中获取资源,在这期间若资源产生了变化,浏览器就在缓存期内就一直得不到最新的资源,那么如何防止这种事情发生呢?
通过更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。
这样每次文件改变后就会生成新的query值,这样query值不同,也就是页面引用的资源路径不同了,之前缓存过的资源就被浏览器忽略了,因为资源请求的路径变了。