我们整天和浏览器和打交道,应该都听过强缓存和协议缓存,强缓存和协商缓存(也有叫对比缓存)都是浏览器的缓存策略,需要先明确一点,既然是浏览器的缓存,缓存的数据都是存放于客户端的机子上的,只是根据优先级不同,存储位置不同,还可以进行细分而已,比如 Service Worker(代理缓存),Memory Cache(内存缓存),Disk Cache(磁盘缓存)!
当我们打开一个页面时候,请求回来了html、css、js、图片等文件,会把这些文件储存在本地缓存中,当我们下次打开这个页面的时候,就可以直接从缓存中读取这些文件,不用再去服务器请求了!
优点:
缺点:
一般js文件,图片都储存在内存中,因为可能频繁要用到,所以内存中读取比较快!
特点:
顾名思义就是储存在磁盘(电脑中),当下次访问的时候就不需要重新下载,直接从磁盘中读取!一般非脚本文件会储存在磁盘中(如css等),因为css只加载一次就渲染出来了,不会频繁读取他,想脚本文件,图片就不适合存在磁盘中,因为脚本文件可能随时执行(一个点击操作事件就触发脚本),如果放在磁盘中,还需要从磁盘取到内存中,这样就需要I/O操作(input读取,读到这个文件,output写入,然后拷贝到内存),这个过程比较慢了,很可能浏览器会失去响应!
特点:退出进程,数据不会清空
来操作一波看下面图:
以百度网站为例,第一次刷新,内存和磁盘都没有资源,去请求网络资源,当我刷新后,先去内存中找资源,找到了,显示状态200(from memory cache),然后我再关闭这个网页,重新打开百度网站,然后文件状态200(from disk cache)
顾名思义强(强求)缓存,如果命中强缓存且未过期,那么直接读取缓存资源!这里有个条件是未过期!什么未过期?那就要引入head中两个属性expires和cache-control
expires
这个http 1.0规范,是个绝对时间 比如 Sat Aug 01 2020 16:13:03 GMT 好比你在超市买了瓶饮料,饮料瓶盖上会有个过期时间(2021,6,6),到了这个时间就过期了,不能喝了!(但是有些人可能不知道今天是几月几号,混日子过的?),看下图:
这里告诉浏览器这个文件到2030年 6月26 星期3 11点37份1秒(标准时间)才过期,没到这个时间,你都可以在缓存中取!
缺点:如果服务端的时间和客户端的时间不一致就会导致缓存混乱问题,所以http1.1中引入了cache-control
cache-control
这个http 1.1出现head的属性,看英文意思是缓存控制,它有几种形式:
如果cache-control与expires同时存在的话,cache-control的优先级高于expires!看下强缓存的执行流程:
顾名思义就是要协商下(要和服务器商量下),如果服务器同意了,我就用本地缓存,如果不同意,那没办法,乖乖请求最新的资源回来,接下来要引入两个属性 ETag 和 Last-Modified
Last-Modified
最后的修改时间,当我们第一次去发送请求后,服务器会再响应头里面带上这个文件的Last-Modified,当我们再次请求这个文件时候,会在请求头里面带上If-Modified-Since(就是之前响应头的Last-Modified,只是名字变了),如果两个时间相同就说明这个文件没有改过!那么用本地缓存吧!如果时间不对,还是乖乖请求最新的资源回来吧!看下图:
看下请求的状态(304):
这里请求头中的文件和响应头的时间一样的,所以读取本地缓存,服务器返回的状态是304(注意协商缓存需要和服务器打下交道,把时间传过去,服务器对比时间,如果相同用缓存,不会返回内容)
缺点: 比如在秒以下的时间内进行修改,(比方说1s内修改了N次),If-Modified-Since能检查到的是s级的,或者某些服务器不能精确的得到文件的最后修改时间,又或者一些文件只是修改了时间并没有改变内容,这个时候我们并不希望客户端认为这个文件被修改了,而重新去请求新资源!这些Last-Modified是无法判断的,那么就引入了ETag
ETag
你可以把它看成md5戳,每个文件都有个,如果文件改了那么这个md5值也改变了(文件的唯一标识)
操作流程和Last-Modified类似的!
缺点:每次客户端发出请求,服务端都会根据资源重新生成一个Etag,对性能有影响,可能会给服务器带来更大的负担
有时候会两个一起用,每次请求文件,每次http返回来 response header 中的 ETag和 Last-Modified,在下次请求时在 request header 就把这两个带上(但是名字变了ETag–>If-None-Match,Last-Modified–>If-Modified-Since ),服务端把你带过来的标识和资源目前的标识进行对比,然后判断资是否返回状态304还是200(请求最新资源)!看下图:
如果浏览器访问之前已经访问的资源,我们来总结下流程:
cache-control在请求头和响应头的含义不一样,拿cache-control:max-age =no-cache来说吧!
请求头:表示浏览器不读取缓存,直接发送请求获取最新资源
响应头:表示不使用强缓存,默认使用协商缓存。
所以为什么 ctrl+F5可以跳过强缓存和协商缓存,看下图:
最后总结下用户操作对浏览器缓存的影响
地址回车 | 页面跳转链接 | 新打开窗口 | 回退 | 前进 这些操作对强缓存和协商缓存都有效! F5刷新会跳过强缓存,对协商缓存有效! ctrl+F5对对强缓存和协商缓存无效!
参考文献: