查漏补缺——浏览器缓存

159 阅读8分钟

浏览器缓存机制也叫做HTTP缓存机制 image

  1. 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识,如果不存在该缓存结果和缓存标识,强制缓存失败,则直接向服务器发起请求
  2. 第一次请求成功,浏览器从服务器下载资源文件,并缓存资源文件与缓存标识,以供下次加载时对比使用
  3. 下一次加载资源时,由于强制缓存优先级较高,先比较当前时间与上一次返回200时的时间差,如果没有超过cache-control设置的max-age,则没有过期,并命中强缓存,直接从本地读取资源。如果浏览器不支持HTTP1.1,则使用expires头判断是否过期
  4. 如果资源已过期,则表明强制缓存没有被命中,则开始协商缓存,向服务器发送带有lf-None-Match 和lf-Modified-Since的请求
  5. 服务器收到请求后,优先根据Etag 的值判断被请求的文件有没有做修改,Etag值一致则没有修改,命中协商缓存,返回304;如果不一致则有改动,直接返回新的资源文件带上新的Etag值并返回200
  6. 如果服务器收到的请求没有 Etag 值,则将lf-Modified-Since和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回304;不一致则返回新的last-modified和文件并返回200 image

强缓存

当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中和请求结果一起返回给浏览器,控制强缓存的字段分别是expires和cache-control

Expires

Expires是HTTP/1.0控制网页缓存的字段,其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果
到了HTTP/1.1,Expire已经被Cache-Control替代,原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,那么如果客户端与服务端的时间因为某些原因(例如时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存则会直接失效,这样的话强制缓存的存在则毫无意义

Cache-Control

在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存,主要取值为:

  • public:所有内容都将被缓存(客户端和代理服务器都可缓存)
  • private:所有内容只有客户端可以缓存,Cache-Control的默认取值
  • no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
  • no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
  • max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效 由于Cache-Control的优先级比expires,那么直接根据Cache-Control的值进行缓存,意思就是说在600秒内再次发起该请求,则会直接使用缓存结果,强制缓存生效。
    注:在无法确定客户端的时间是否与服务端的时间同步的情况下,Cache-Control相比于expires是更好的选择,所以同时存在时,只有Cache-Control生效

协商缓存

协商缓存需要在服务器端对比资源是否修改,来判断是否可以使用缓存。若未改动,则返回304状态码,浏览器拿到此状态码就可以直接使用缓存数据了。如果资源发生了改动,则返回修改过后的资源

Last-Modified/If-Modified-Since

服务器通过在响应头中添加Last-Modified属性来指出资源最后一次修改的时间 当浏览器下一次发起请求时,会在请求头中添加一个lf-Modified-Since的属性,属性值为上一次资源返回时的Last-Modified的值 当请求发送到服务器后,服务器会通过这个属性来和资源的最后一次的修改时间来进行比较,以此来判断资源是否做了修改 如果资源没有修改,那么返回304状态,让客户端使用本地的缓存 如果资源已经被修改了,则返回修改后的资源 使用这种方法有一个缺点,就是Last-Modified标注的最后修改时间只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,那么文件已将改变了但是Last-Modified却没有改变,这样会造成缓存命中的不准确

Etag/If-None-Match

因为Last-Modified的这种可能发生的不准确性,http中提供了另外一种方式,那就是**Etag** 属性 服务器在返回资源的时候,在头信息中添加了**Etag** 属性,这个属性是资源生成的唯一标识符,当资源发生改变的时候,这个值也会发生改变 在下一次资源请求时,浏览器会在请求头中添加一个lf-None-Match属性,这个属性的值就是上次返回的资源的**Etag** 的值。服务接收到请求后会根据这个值来和资源当前的Etag的值来进行比较,以此来判断资源是否发生改变,是否需要返回资源。这种方式比Last-Modified的方式更加精确

当Last-Modified和Etag属性同时出现的时候,Etag 的优先级更高。使用协商缓存的时候,服务器需要考虑负载平衡的问题,因此多个服务器上资源的Last-Modified应该保持一致,因为每个服务器上Etag 的值都不一样,因此在考虑负载平衡时,最好不要设置Etag属性

总结强缓存与协商缓存

强缓存策略和协商缓存策略在缓存命中时都会直接使用本地的缓存副本,区别只在于协商缓存会先向服务器发送一次请求。它们缓存不命中时,都会向服务器发送请求来获取资源。在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则浏览器返回最新的资源给浏览器

浏览器缓存的优点

浏览器缓存指的是浏览器将用户请求过的静态资源,存储到电脑中,当浏览器再次访问时,直接从本地加载,不需要再去服务端请求了

  • 减少了服务器的负担,提高了网站的性能
  • 加快了客户端网页的加载速度
  • 减少了多余的网络数据传输
  • 减少了请求次数

几种刷新方式的区别

  • 点击刷新或F5:浏览器直接对本地文件过期,但是请求头会携带lf-None-Match和lf-Modified-Since,服务器会检查文件的新鲜度,返回结果可能是304或200
  • Ctrl+F5(强制刷新):浏览器不仅会对本地文件进行过期,请求时也不会带上lf-None-Match和lf-Modified-Since,相当于之前从来没有请求过
  • 地址栏回车:浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查文件新鲜度,最后返回内容

浏览器缓存在内存中的位置

from memory cache——代表使用内存中的缓存 from disk cache——代表使用硬盘中的缓存 浏览器读取的顺序为memory->disk 内存缓存:内存缓存具有快速读取时效性两个特点

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

硬盘缓存:硬盘缓存则是直接将缓存写入硬盘文件中,读取缓存需要对该缓存存放的硬盘文件进行I/O操作,然后重新解析该缓存内容,读取复杂,速度比内存缓存慢 在浏览器中,浏览器会在JS和图片等文件解析执行后直接存入内存缓存中,那么当刷新页面时只需要直接从内存缓存中读取,而CSS文件则会存入硬盘文件中

参考文章

juejin.cn/post/694793…

juejin.cn/post/684490…