关于前端http缓存的使用及分类

web缓存主要指的是两部分:浏览器缓存http缓存

浏览器缓存一般指localStorage,sessionStorage,cookie等,主要用于缓存一些必要数据在客户端,有大小的容量限制。

http缓存主要是针对html,css,img等静态资源,常规情况下,我们不太会去缓存一些动态资源,因为缓存动态资源的话,数据的实时性就不能保证,所以我们一般都只会去缓存一些不太容易被改变的静态资源。

http缓存是可以自动保存常见文档副本的HTTP设备。当web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地存储设备而不是原始服务器中提取这个文档,是web缓存的核心,接下来就重点介绍该部分。

一、http缓存的优缺点是什么?有哪些分类?

优点:

  • 减少不必要的网络传输,节约带宽(省钱)
  • 更快的加载页面(加速)
  • 减少服务器负载,避免服务器过载的情况出现(减载)

缺点:

  • 占内存(有些缓存会被存到内存中)

其实日常的开发中,最关心的还是“更快的加载页面”;尤其是对于vue/react等SPA(单页面)应用来说,首屏加载是老生常谈的问题。这个时候,缓存就显得非常重要,不需要往后端请求,直接在缓存中读取,速度上无疑会有显著的提升,是一种提升网站性能与用户体验的有效策略。

分类:

  • 强制缓存(强缓存)
  • 协商缓存

二、强制缓存

从强制缓存的角度出发,如果浏览器判断请求的目标资源有效命中强缓存,如果命中,则可以直接从内存中读取目标资源,无需与服务器做任何通讯。

1、基于Expires字段实现的强缓存(该属性已被废弃,不推荐使用)

Expires字段的作用是,设定一个强缓存时间,在此时间范围内,则从内存(或磁盘)中读取缓存返回,比如将某一资源设置响应头为:Expires:new Date("2023-2-2 23:59:59");那么,该资源在该时间之前,都会去本地内存(或磁盘)中读取,不会去服务器请求。

由于Expires判断强缓存是否过期的机制是:获取本地时间戳,并对先前拿到的资源文件中的Expires字段的时间做比较,来判断是否需要对服务器发起请求,从而导致一个严重漏洞:“如果本地时间不准呢?”

2、基于Cache-control实现的强缓存(代替Expires的强缓存实现方法,推荐)

Cache-control在http1.1中被增加,完美解决了Expires本地时间和服务器时间不同步的问题,是当下项目中实现强缓存的最常规方法。Cache-control:max-age=N,N就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存)中读取,不与服务器做任何交互。

Cache-control的六个属性:

  • max-age决定客户端资源被缓存多久
  • s-maxage决定代理服务器缓存的时长(由于是代理服务器的缓存时长,因此必须与public属性一起使用)
  • no-cache表示强制进行协商缓存
  • no-store表示禁止任何缓存策略(与no-cache互斥)
  • public表示资源既可以被浏览器缓存也可以被代理服务器缓存
  • private表示资源只能被浏览器缓存(与public互斥)

注意:Cache-control设置多个值时,各属性间使用逗号分割,如:Cache-control:max-age=10000,s-maxage=200000,public

三、协商缓存(需要将cache-control设置为no-cache)

1、基于last-modified的协商缓存(通过比对资源文件的修改时间进行协商缓存)

使用last-modified和If-Modified-Since实现

流程:

  • 首先需要在服务器端读出文件修改时间
  • 将读出来的修改时间赋给响应头的last-modified字段
  • 最后设置Cache-control:no-cache

以上三步缺一不可,且均在服务器端代码中实现。实现完以上三步后,当客户端读取到last-modified的时候,会在下次的请求头中携带一个字段:If-Modified-Since,这个字段的值就是服务器第一次修改时候给它的时间,之后每次对该资源的请求,都会带上If-Modified-Since这个字段,而服务端就需要拿到这个时间并再次读取该资源的修改时间,两个时间进行对比之后决定是读取缓存还是返回新的资源。

缺点(这两个漏洞都是基于文件是通过比较修改时间来判断是否更改而产生的):

  • 在文件内容本身不修改的情况下,依然有可能更新文件修改时间(比如修改文件名再改回来),此时文件内容并没有修改,缓存依然失效了
  • 因为文件修改时间记录的最小单位是秒,所以当文件在几百毫秒内完成修改的时候,文件修改时间并不会改变,这样,即使文件内容修改了,依然不会返回新的文件

2、基于ETag的协商缓存(通过生成文件内容的唯一哈希值,即文件指纹进行协商缓存)

使用ETag和If-None-Match实现

ETag就是将原先协商缓存的比较时间戳的形式修改成了比较文件指纹。

流程:

  • 第一次请求某资源的时候,服务端读取文件并计算出文件指纹,将文件指纹放在响应头的ETag字段中跟资源一起返回给客户端
  • 第二次请求某资源的时候,客户端自动从缓存中读取出上一次服务端返回的ETag也就是文件指纹。并赋给请求头的If-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端
  • 服务端拿到请求头中的If-None-Match字段值(也就是上一次的文件指纹),并再次读取目标资源并生成文件指纹,两个指纹做对比。如果两个文件指纹完全吻合,说明文件没有被改变,则直接返回304状态码和一个空的响应体并return。如果两个文件指纹不吻合,则说明文件被更改,那么将新的文件指纹重新存储到响应头的ETag中并返回给客户端

缺点:

  • 需要文件尺寸大,数量多,并且计算频繁,那么服务端就需要更多的计算开销,从而影响服务器的性能
  • ETag有强验证和弱验证,所谓强验证,ETag生成的哈希值深入到每个字节,从而保证文件内容绝对的不变,非常消耗计算量;弱验证则是提取文件的部分属性来生成哈希值,因此不必精确到每个字节,所以整体速度会比强验证快,但是精确率不高,会降低协商缓存的有效性

四、哪些文件对应哪些缓存

有哈希值的文件设置强缓存,没有哈希值的文件(如index.html)设置协商缓存

五、总结

  • http缓存可以减少带宽流量,加快响应速度
  • 关于强缓存,cache-control是expires的完全替代方案,在可以使用cache-control的情况下就不要使用expires
  • 关于协商缓存,ETag并不是last-modified的完全替代方案,而是补充方案,具体用哪一个,取决于项目业务场景,无孰好孰坏之分
  • 有些缓存是从磁盘读取,有些缓存是从内存读取;从内存读取的缓存更快
  • 所有带304的资源都是协商缓存,所有标注(从内存/磁盘中读取)的资源都是强缓存
posted @ 2023-02-02 14:19  阿彬~  阅读(293)  评论(0编辑  收藏  举报