背景

为什么需要缓存

  • 减少请求服务器次数,提升用户体验

缓存过程分析

  • 浏览器向服务器发起请求,首先会去检查浏览器是否有缓存(第一次请求不存在缓存,但还是要检查才知道),如果存在并且生效则直接使用(强缓存),如果存在不生效则需要进行协商缓存,经服务器判断缓存生效,则直接使用缓存,不生效需要重新向服务器请求资源,拿到新的资源后重新存入浏览器缓存
  • 服务器会在响应头中设置缓存规则(强缓存和协商缓存),还会携带浏览器请求的资源
  • 浏览器收到响应之后,会根据缓存规则将资源存储起来(内存存储和硬盘存储)
  • 如果缓存没过期,下次请求会直接使用缓存

强缓存

强缓存就是向浏览器查找当前请求资源的缓存,并根据找到的缓存结果的规则来决定是否使用(是否已过期)该缓存的一个过程,总共会有三种情况

  • 第一种。不存在缓存标识和结果,强缓存失败,直接向服务器请求资源
  • 第二种。存在缓存结果和标识,但是该结果已经失效,强缓存失败,向服务器请求资源
  • 第三种。存在缓存结果和标识并且有效,强缓存生效,使用缓存作为资源,不向服务器请求资源

expires

  • expiresHTTP1.0控制网页缓存的字段,其值为服务器返回的结果的到期时间.当客户端在次请求资源时,如果客户端的时间小于这个字段的值,则直接使用缓存,否则相反.
  • 到了HTTP1.1expires字段已经被Cache-Control字段代替.原因是expires控制缓存的原理是用客户端时间与服务端返回的缓存到期时间进行对比,服务端时间是固定不变的,但是客户端时间可能会因为时区等因素导致不一样,可能会导致缓存失效.

Cache-Control

  • public,所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private,所有内容只有客户端可以缓存,默认值
  • no-cache,客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store,所有内容都不会被缓存,强缓存和协商缓存都没有
  • max-age=xxx,缓存内容将在 xxx 秒后到期,解决了时区不同导致的问题
  • Cache-Control 的优先级大于 Expires,如果两者同时出现使用 Cache-Control

协商缓存

协商缓存就是在强缓存失效后,带着缓存标识向服务器发起请求,服务器根据缓存表示判断是否使用缓存的过程

协商缓存生效(缓存内容没发生变化),返回 304

协商缓存失效(缓存内容发生变化),返回 200

Last-Modified / if-Modified-Since

  • Last-Modified字段是服务器响应请求时,返回该资源在服务器上最后被修改的时间
  • if-Modified-Since客户端请求资源时放在请求头中的字段,值为该资源上次被修改的时间(Last-Modified 的值).服务端收到请求后,如果请求头中有这个字段,则用这个字段的值和该资源在服务器上最后被修改的时间做比较,如果前者小于后者,则表示该资源有修改返回 200,反之就是没有修改,返回 304

Etag / if-None-Match(优先级高)

  • Etag服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)
  • if-None-Match是客户端请求资源时放在请求头中的字段,值为该资源的唯一标识(上次请求返回的 Etag 值).服务器收到请求后,如果请求头中有if-None-Match字段,则用该字段值与当前服务器资源的唯一标识进行对比,如果相同,表示资源没有发生变化,返回 304.如果不相同,表示资源有变化,返回 200

存储位置

内存缓存具有两个特点,分别是快速读取和时效性:

  • 快速读取:内存缓存会将编译解析后的文件,直接存入该进程的内存中,占据该进程一定的内存资源,以方便下次运行使用时的快速读取。
  • 时效性:一旦该进程关闭,则该进程的内存则会清空。

硬盘存储

  • 硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行 I/O 操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢。

在浏览器中,浏览器会在 js 和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需直接从内存缓存中读取(from memory cache);而 css 文件则会存入硬盘文件中,所以每次渲染页面都需要从硬盘读取缓存(from disk cache)。