今天看啥  ›  专栏  ›  影子同学

前端客户端缓存相关的总结

影子同学  · 掘金  ·  · 2019-05-19 14:38
阅读 43

前端客户端缓存相关的总结

这里主要记录在日常中对知识的学习,通过结合笔记与自身理解的方式尝试写下总结
文章对细节可能不会一一介绍解释,内容仅作参考
复制代码

前些日子在面试的时候被问到有关前端优化的,其中回答了利用前端缓存,接着就被追问有关缓存的一些问题,但回答得不是很好,有必要再整理理解一下。由于目前只查阅了有关客户端缓存相关的知识,所以接下来内容都是围绕着它来讲。当然了,其他方式的缓存也是要学习的

一、缓存的分类

平时中一般说的都是客户端缓存,当然啦,还有其他类别的。此处提供了解:

  • CDN缓存
  • DNS缓存
  • 客户端缓存
  • Service Worker与缓存及离线缓存
  • PageCache与ajax缓存

二、缓存的作用

使用缓存有如下优化:

  • 减少冗余的数据传输
  • 节省网络费用,缓解网络瓶颈问题
  • 降低对原始服务器的要求,服务器可以更快响应,避免出现过载

缓存有时候也可能会带来不想要的结果,比如使用了缓存的数据导致无法实时呈现效果
也不能说是好坏,可以当成一个工具,想发挥什么样的作用,关键是看我们怎么使用它

三、客户端缓存

客户端缓存方式主要分为强缓存协商缓存两种

  • 强缓存:将资源缓存到本地。再次请求时,直接使用本地的缓存(不用跟服务器进行通信)
  • 协商缓存:缓存资源到本地并保存该资源的缓存信息。再次请求时,将资源相关信息返回给服务器,让服务器判断浏览器是否能直接使用本地缓存(整个过程至少与服务器通信一次)
    • 如果能,直接使用本地的缓存
    • 如果不能,再次请求服务器获取最新的资源

客户端缓存操作过程如下:

1.浏览器首次请求资源:

  • 本地无资源,向服务器获取对应数据
  • 在获取到资源后,会根据 响应的header内容 来决定缓存该资源的方式(是否缓存,要缓存的话是使用强缓存还是协商缓存)

2.浏览器后续请求资源:

  • 先获取该资源缓存的header信息,判断是否命中缓存(根据cache-controlexpires信息判断),若命中,直接从缓存中获取资源信息,包括缓存header信息。本次请求不会与服务器进行通信 (强缓存)
  • 如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否缓存命中,若命中则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取 (协商缓存)
  • 否则从服务器获取最新的资源内容

可以用图来更具体地说明一下:

浏览器首次请求资源

浏览器后续请求资源

四、强缓存

与强缓存主要相关的header字段有expirescache-control:max-age=number。并且如果cache-control与expires同时存在的话,cache-control的优先级高于expires

  • expires:这是http1.0时的规范,它的值为一个绝对时间的GMT格式的时间字符串,如Tue May 14 2019 00:00:10 GMT,如果获取时间在expires之前,本地缓存有效,反之过期
  • cache-control:max-age=number:这是http1.1时出现的header信息,主要是利用该字段的max-age值来进行判断,它是一个时间相对值。资源第一次的请求时间和Cache-Control设定的有效期时间,计算出一个资源过期时间。通过这个过期时间跟当前的请求时间比较,如果请求时间在过期时间之前,本地缓存有效,反之过期。cache-control除了该字段外,还有下面几个比较常用的设置值:
    • 1)no-cache:不使用本地缓存
    • 2)no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源
    • 3)public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器
    • 4)private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存

五、协商缓存

与协商缓存相关的header字段有Last-Modified/If-Modified-SinceEtag/If-None-Match
协商缓存是由服务器来确定缓存资源是否可用的,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问,这主要涉及到上面两组header字段,这两组搭档都是成对出现的
即第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或者If-None-Match),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段

  • Last-Modified/If-Modified-Since: 二者的值都是GMT格式的时间字符串,具体过程:
    • 1)浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在respone的header加上Last-Modified的header,这个header表示这个资源在服务器上的最后修改时间
    • 2)浏览器再次跟服务器请求这个资源时,在request的header上加上If-Modified-Since的header,这个header的值就是上一次请求时返回的Last-Modified的值
    • 3)服务器再次收到资源请求时,根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header中不会再添加Last-Modified的header,因为既然资源没有变化,那么Last-Modified也就不会改变,这是服务器返回304时的response header
    • 4)浏览器收到304的响应后,就会从缓存中加载资源
    • 5)如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified的Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值
  • Etag/If-None-Match: 这两个值是由服务器生成的每个资源的唯一标识字符串,当资源有变化时,这个值就会改变;其判断过程与Last-Modified/If-Modified-Since类似,与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化

Last-Modified和Etag的区别 在描述中对于Last-Modified和Etag的使用可以说是差不多的,但是,Etag(http1.1)的出现是为了解决几个Last-Modified比较难解决的问题:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新GET
  • 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的粒度是s级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)
  • 某些服务器不能精确的得到文件的最后修改时间 这时,利用Etag能够更加准确的控制缓存,因为Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符

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

六、强缓存和协商缓存的区别

七、缓存位置

缓存的位置大致分为以下三类:Service Worker,Memory Cache,Disk Cache 并且它们的优先级就是按照这个顺序,从前往后寻找,找到即返回;找不到则继续。若最后资源在这些地方都没有找到的话,再去服务器请求资源

  • service worker
    用户自定义缓存哪些资源到硬盘上,什么情况下使用缓存(路由匹配规则),缓存匹配并返回
    清空缓存的情况分两种:一是手动调用api,二是容量超过限制,被浏览器清除
    这种方式缓存的资源查看方式:开发者工具 -> Application -> Cache Storage
    当资源请求被发起的时候,浏览器首先从service worker中查找资源,如果缓存为命中,一般情况会使用fetch()方法继续获取资源,这时浏览器就去memory cache 或disk cache中进行下一次找缓存的工作
    特别注意:经过fetch()方法获取的资源,都会显示 from ServiceWorker,不管资源实际情况是从memory cache 或disk cache,还是从网络重新请求获取的

  • memory cache
    内存中的缓存,几乎所有的网络请求资源都会被浏览器自动加入到memory cache中,被短期存储,关闭浏览器窗口后memory cache就失效了
    从memory cache中获取缓存内容的时候,浏览器会忽视例如max-age=0,no-cache等头部配置
    但如果头部配置设置了no-store,那么资源就不会进入memory-cache

  • disk cache
    硬盘上的缓存,持久存储,允许相同资源跨回话跨站点的使用
    严格根据HTTP头部字段判定该缓存哪些资源,哪些资源可用,以及哪些资源过期了需要重新请求
    当请求命中缓存时,就从硬盘中读取资源。绝大多数的缓存都来自disk cache

查询咨询来源:

  • Chrome开发工具 -> network -> 查看size那一列的值

  • xxk:网络请求

  • form memory cache

  • disk cache

  • from ServiceWorker

八、不缓存的方式

  1. meta设置
<META HTTP-EQUIV="pragma" CONTENT="no-cache"> 
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> 
<META HTTP-EQUIV="expires" CONTENT="0">
复制代码
  1. ajax请求中的请求头加入取消缓存设置
If-Modified-Since: 0
Cache-Control: no-cache
复制代码
  1. ajax请求url后加入随机数或时间戳参数
url + ? ran = Math.random()/new Date().getTime()
复制代码
  1. 后端返回响应头相关参数设置



原文地址:访问原文地址
快照地址: 访问文章快照