一、web缓存(前端缓存)
访问服务器获取数据都是很常见的事情,如果相同的数据被重复请求了不止一次,那么多余的请求必然会浪费网络带宽,以及延迟浏览器渲染所要处理的内容,从而影响用户的使用体验。(为什么需要缓存)
(1)定义
web缓存就是存在于客户端与服务器之间的一个副本、当你第一个发出请求后,缓存根据请求保存输出内容的副本。
(2)分类
前端缓存主要是分为HTTP缓存和浏览器缓存。其中HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置;而浏览器缓存则主要由前端开发在前端js上进行设置。
(2.1)浏览器缓存
浏览器缓存则主要由前端开发在前端js上进行设置。
浏览器缓存:比如:localStorage,sessionStorage,cookie等等。这些功能主要用于缓存一些必要的数据,比如用户信息。比如需要携带到后端的参数。亦或者是一些列表数据等等。
不过这里需要注意。像localStorage,sessionStorage这种用户缓存数据的功能,他只能保存5M左右的数据,多了不行。cookie则更少,大概只能有4kb的数据。
(2.2)http缓存
HTTP缓存是在HTTP请求传输时用到的缓存,主要在服务器代码上设置。
http缓存是web缓存的核心,是最难懂的那一部分,也是最重要的那一部分。
(2.3)CDN缓存
(2.4)代理服务器缓存
(3)缓存的优缺点
如下图所示,服务器需要处理http的请求,并且http去传输数据,需要带宽,带宽是要钱买的啊。而我们缓存,就是为了让服务器不去处理这个请求,客户端也可以拿到数据。
注意,我们的缓存主要是针对html,css,img等静态资源,常规情况下,我们不会去缓存一些动态资源,因为缓存动态资源的话,数据的实时性就不会不太好,所以我们一般都只会去缓存一些不太容易被改变的静态资源。
缓存的好处(解决的问题):
- 省钱:减少不必要的http的请求,节约宽带
- 减载:减少服务器负载,避免服务器过载的情况出现
- 加速:降低网络延迟,更快的加载页面(直接读取浏览器的数据)
缺点:
- 占内存(有些缓存会被存到内存中)
二、http缓存
(1)缓存原理
缓存的原理是在首次请求后保存一份请求资源的响应副本,当用户再次发起相同请求后,如果判断缓存命中则拦截请求,将之前存储的响应副本返回给用户,从而避免了重新向服务器发起资源请求。
(2)http缓存分类与流程
HTTP缓存应该算是前端开发中最常接触的缓存之一,它又可以细分为强制缓存和协商缓存,二者最大的区别在于判断缓存命中时,浏览器是否需要向服务器端进行询问以协商缓存的相关信息,进而判断是否需要就响应内容进行重新请求,下面让我们来看看HTTP缓存的具体机制及缓存的决策策略。
http缓存流程图:
- 当浏览器发起一个资源请求时,浏览器会先判断本地是否有缓存记录,如果没有会向浏览器请求新的资源,并记录服务器返回的last-modified。
- 如果有缓存记录,先判断强缓存是否存在(cache-control优先于expires,后面会说),如果强缓存的时间没有过期则返回本地缓存资源(状态码为200)
- 如果强缓存失效了,客户端会发起请求进行协商缓存策略,首先服务器判断Etag标识符,如果客户端传来标识符和当前服务器上的标识符是一致的,则返回状态码 304 not modified(不会返回资源内容)
- 如果没有Etag字段,服务器会对比客户端传过来的if-modified-match,如果这两个值是一致的,此时响应头不会带有last-modified字段(因为资源没有变化,last-modified的值也不会有变化)。客户端304状态码之后读取本地缓存。如果last-modified。
- 如果Etag和服务器端上的不一致,重新获取新的资源,并进行协商缓存返回数据。
(3)缓存决策及注意事项
注意事项:
假设在不考虑客户端缓存容量与服务器算力的理想情况下,我们当然希望客户端浏览器上的缓存触发率尽可能高,留存时间尽可能长,同时还要Etag实现当资源更新时进行高效的重新验证。但实际情况往往是容量与算力都有限,因此就需要制定合适的缓存策略,来利用有限的资源达到最优的性能效果,明确能力的边界,力求在边界内做到最好。
在面对一个具体的缓存需求时,我们可以参照如下的缓存决策树来逐步确定对一个资源具体的缓存策略。
- 是否使用缓存
- 否:no-store
- 是:
- 是否进行协商缓存
- 是:no-cache
- 否
- 是否会被代理服务器缓存
- 是:public(
- 否:private
- 配置强制缓存过期时间
- 配置协商缓存的Etag或last-modified。
- 配置强制缓存过期时间
- 是否会被代理服务器缓存
- 是否进行协商缓存
no-store:禁止使用缓存
no-cache:协商缓存
public:响应资源既可以被浏览器缓存,又可以被代理服务器缓存
private:限制了响应资源只能被浏览器缓存
public与private互斥,不设置默认是private
Etag:比较文件指纹(由文件内容计算出的唯一哈希值)
last-modified:比较修改资源文件的时间戳
Etag并不是last-modified的完全替代方案,而是补充方案,具体用哪一个,取决于业务场景。
缓存位置
从缓存位置上来说分为四种,并且各自有优先级,当依次查找缓存且都没有命中的时候,才会去请求网络。
- Service Worker
- 行在浏览器背后的独立线程,一般可以用来实现缓存功能
- 因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全
- Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
- Memory Cache
- 内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。
- 读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。
- 一旦我们关闭 Tab 页面,内存中的缓存也就被释放了
- 访问过页面以后,再次刷新页面,可以发现很多数据都来自于内存缓存
- Disk Cache
- Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点
- Disk Cache 比Memory Cache胜在容量和存储时效性上。
- 在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的
- 它会根据 HTTP Herder 中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。
- Push Cache
- Push Cache是推送缓存,是 HTTP/2 中的内容
- 只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂
- 在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。
如果以上四种缓存都没有命中的话,那么只能发起请求来获取资源了。
那么为了性能上的考虑,大部分的接口都应该选择好缓存策略,通常浏览器缓存策略分为两种:强缓存和协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。
(4)http缓存-强缓存
对于强制缓存而言,如果浏览器判断所请求的目标资源有效命中,则直接从强制缓存中返回请求响应,无须与服务器进行任何通信。返回200的状态码。
在浏览器控制台
NetWork中的体现为:
200 OK (from disk cache)或者200 OK (from memory cache)
释义
200 OK (from disk cache)HTTP状态码200,缓存的文件从硬盘中读取200 OK (from memory cache)HTTP状态码200,缓存的文件从内存中读取
强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control。
(4.1)基于expires实现
缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。 Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
- 在以前,我们通常会使用响应头的
Expires字段去实现强缓存,现在的项目中基本上不推荐使用expires - HTTP1.0协议中声明的用来
控制缓存失效日期时间戳的字段 - 由服务器端指定后通过响应头告知浏览器,浏览器在接收到带有该字段的响应体后进行缓存。
- 如果浏览器再次发起相同的资源请求,便会对比
expires与本地当前的时间戳。- 当前请求的本地时间戳小于expires的值,则说明浏览器缓存的响应还未过期,无须向服务器端再次发起请求
- 当本地时间戳大于expires值,缓存过期,重新向服务器发起请求。(仅过期才能允许再次发送请求)
- expires判断的局限性:
- 对本地时间戳过分依赖
- 如果客户端本地的时间与服务器端的时间不同步,或者对客户端的时间进行主动修改,那么对于缓存过期的判断可能就无法和预期相符。
- 解决expires判断的局限性:HTTP1.1协议开始新增了
cache-control字段- 比如:cache-control设置了maxage=31536000的属性值来控制响应资源的有效期,它是一个以秒为单位的时间长度,表示该资源在被请求到后的31536000秒内有效,如此便可避免服务器端和客户端时间戳不同步而造成的问题。
(4.2)基于cache-control实现
在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存。比如当Cache-Control:max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。
Cache-Control:max-age=N,N就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。
Cache-control中因为max-age后面的值是一个滑动时间,从服务器第一次返回该资源时开始倒计时。所以也就不需要比对客户端和服务端的时间,解决了Expires所存在的巨大漏洞。
基于cache-control实现的强缓存是当下项目中的常规方法,而基于expires实现的强缓存不被推荐使用。
Cache-Control 可以在请求头或者响应头中设置,并且可以组合使用多种指令
cache-control的参数:
- 1.
max-age:(单位为s)表示响应资源能被缓存多久max-age和expires同时存在,则以max-age为准
- 2.
s-maxage:(单位为s)缓存在代理服务器中的过期时长(仅当设置了public属性值时才是有效的)- max-age和s-maxage并不互斥。他们可以一起使用
- 3.
no-cache:强制进行协商缓存- Cache-control中设置了no-cache,那么该资源会直接跳过强缓存的校验,直接去服务器进行协商缓存
- 4.
no-store:禁止使用任何缓存- 客户端的每次请求都需要服务器端给予全新的响应
no-cache与no-store是两个互斥的属性值,不能同时设置
- 5.
public:表示响应资源既可以被浏览器缓存,又可以被代理服务器缓存 - 6.
private:限制了响应资源只能被浏览器缓存- public和private就是决定资源是否可以在代理服务器进行缓存的属性
- 如果这两个属性值都没有被设置,则默认为private
- public和private 也是一组互斥属性
Cache-control如何设置多个值呢?用逗号分割
Cache-control:max-age=10000,s-maxage=200000,public
如果要考虑向下兼容的话,在Cache-control不支持的时候,还是要使用Expires,这也是我们当前使用的这个属性的唯一理由。
(4.3)强缓存两种方式的区别
- Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
- Expires 是http1.0的产物,Cache-Control是http1.1的产物
- expires/cache-control两者同时存在的话,Cache-Control优先级高于Expires
- 在某些不支持HTTP1.1的环境下,Expires就会发挥用处
- Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法。
(4.4)强缓存的缺陷
强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略。
(5)http缓存-协商缓存
顾名思义,协商缓存就是在使用本地缓存之前,需要向服务器发起一次GET请求,与之协商当前浏览器保存的本地缓存是否已经过期。通常是采用所请求资源的最近一次的修改时间戳来判断的。
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
- 协商缓存生效(文件未更新),返回304和Not Modified。
- 协商缓存失效(文件更新),返回200和请求结果。
协商缓存可以通过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。
(5.1)基于last-modified实现
(5.1.1)实现方式/流程
基于last-modified的协商缓存实现方式是:
- 首先需要在服务器端读出文件修改时间,
- 将读出来的修改时间赋给响应头的
last-modified字段。 - 最后设置
Cache-control:no-cache
第一次请求,服务器端代码
const data = fs.readFileSync('./imgs/CSS.png');//读取资源
// 1.读取修改的时间
const { mtime } = fs.statSync('./imgs/CSS.png');
// 2.设置文件最后修改时间
res.setHeader('last-modified',mtime.toUTCString())
// 3.强制设置为协商缓存
res.setHeader('Cache-Control','no-cache');
res.end(data);
第二次及以后的每一次请求,服务器端代码
const data = fs.readFileSync('./imgs/CSS.png');//读取资源
const { mtime } = fs.statSync('./imgs/CSS.png');//读取修改的时间
const ifModifiedSince = req.headers['if-modified-since'];//读取请求头携带的时间(第一次返回给客户端的文件修改时间)
if (ifModifiedSince === mtime.toUTCString()) {
// 如果两个时间一致,则文件没被修改过,返回304
res.statusCode = 304;
res.end();//因为缓存生效,不需要返回数据
return;// 避免返回新的last-modified
}
res.setHeader('last-modified',mtime.toUTCString())// 设置文件最后修改时间
res.setHeader('Cache-Control','no-cache');// 强制设置为协商缓存
res.end(data);
流程:
- 客户端第一次请求目标资源的时,服务器返回的响应标头包含
last-modified字段,值是该资源的最后一次修改的时间戳,以及cache-control:no-cache - 当客户端再次请求该资源的时候,会携带一个
if-modified-since字段,其值正是上次响应头中last-modified的字段值 - 如果客户端请求头携带的
if-modified-since字段对应的时间与目标资源的时间戳进行对比,如果没有变化则返回一个304状态码。
需要注意的是:协商缓存判断缓存有效的响应状态码是304,但是如果是强制缓存判断有效的话,响应状态码是200。
(5.1.2)last-modified的不足
- last-modified是根据请求资源的最后修改时间戳进行判断的,虽然请求的文件资源进行了编辑,但是内容并没有发生任何变化,时间戳也会更新,从而导致协商缓存时关于有效性的判断验证为失效,需要重新进行完整的资源请求。浪费了网络的带看资源,延长获取资源的时间
- 标识文件资源修改的时间戳单位是秒,如果文件修改的速度非常快,假设在几百毫秒内完成,那么通过时间戳的方式来验证缓存的有效性,是无法识别出该次文件资源的更新的。
综合,以上两种不足可知,基于last-modified实现的协商缓存,服务器无法根据资源修改的时间戳识别出真正的更新,进而导致重新发起了请求
(5.2)基于Etag实现
为了弥补通过时间戳判断的不足,从HTTP1.1规范开始新增了一个Etag的头信息,即实体标签。 其内容主要是服务器为不同的资源进行哈希计算所生成的一个字符串,该字符串类似于文件指纹,只要文件内容编码存在差异,对应的Etag对文件资源进行更精准的变化感知。
也就是说,ETag就是将原先基于last-modified协商缓存的比较时间戳的形式修改成了比较文件指纹。
文件指纹:根据文件内容计算出的唯一哈希值。文件内容一旦改变则指纹改变。
服务端代码
(5.2.1)实现方式/流程
- 第一次请求资源时,服务端将要返回给客户端的数据通过
ETag模块进行哈希计算生成一个字符串,这个字符串类似于文件指纹。 - 第二次请求资源时,客户端自动从缓存中读取出上一次服务端返回的
ETag也就是文件指纹。并赋给请求头的if-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端。 - 检测客户端的请求标头中的
if-None-Match字段的值和第一步计算的值是否一致,一致则返回304。 - 如果不一致则返回etag标头和Cache-Control:no-cache。
(5.2.2)不足
在协商缓存中,Etag并非last-modified的替代方案而是一种补充方案,因为依旧存在一些弊端。
- 服务器对于生成文件资源的Etag需要付出额外的计算开销,如果资源的尺寸比较大,数量较多且修改频繁,那么生成的Etag的过程就会影响服务器的性能。
- Etag字段值的生成分为
强验证和弱验证,强验证根据资源内容进行生成,能够保证每个字节都相同,弱验证则根据资源的部分属性来生成,生成速度快但无法确保每个字节都相同,并且在服务器集群场景下,也会因为准确不够而降低协商缓存有效性的成功率,所以恰当的方式是根据具体的资源使用场景选择恰当的缓存校验方式。
(5.3)Etag/last-modified对比
-
首先在精确度上,Etag要优于Last-Modified。
Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。 -
第二在性能上,Etag要逊于Last-Modified
Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。 -
第三在优先级上,服务器校验优先考虑Etag
(6)怎么设置缓存
缓存是缓存在前端,但实际上代码是后端的同学来写的。如果你需要实现前端缓存的话啊,通知后端的同学加响应头就好了。
(7)http缓存总结
- http缓存可以减少宽带流量,加快响应速度。
- 关于强缓存:cache-control是Expires的完全替代方案,在可以使用cache-control的情况下不要使用expires
- 关于协商缓存:etag并不是last-modified的完全替代方案,而是补充方案,具体用哪一个,取决于业务场景。
- 有些缓存是从磁盘读取,有些缓存是从内存读取,有什么区别?答:从内存读取的缓存更快。
- 所有带304的资源都是协商缓存,所有标注(从内存中读取/从磁盘中读取)的资源都是强缓存。
(8)强缓存协商缓存资源应用分类
频繁变动的资源,首先需要使用Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。
不常变化的资源,给它们的 Cache-Control 配置一个很大的 max-age=31536000 (一年),这样浏览器之后请求相同的 URL 会命中强制缓存。而为了解决更新的问题,就需要在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效 (其实并未立即失效,只是不再使用了而已)。 在线提供的类库 (如 jquery-3.3.1.min.js, lodash.min.js 等) 均采用这个模式。
- HTML: 协商缓存
- css、JS、图片:强缓存,文件名带上哈希
(9)http缓存机制(优先级)
强制缓存优先于协商缓存进行,若强制缓存(Expires和Cache-Control)生效则直接使用缓存,若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回304,继续使用缓存。
(10)用户行为对浏览器缓存的影响
所谓用户行为对浏览器缓存的影响,指的就是用户在浏览器如何操作时,会触发怎样的缓存策略。主要有 3 种:
- 打开网页,地址栏输入地址: 查找 disk cache(硬盘中的缓存) 中是否有匹配。如有则使用;如没有则发送网络请求。
- 普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache(内存中的缓存) 是可用的,会被优先使用(如果匹配的话)。其次才是 disk cache。
- 强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(协商缓存,为了兼容,还带了 Pragma: no-cache),服务器直接返回 200 和最新内容。
三、CDN缓存
(1)什么是CDN?
CDN全称是内容分发网络,它是构建在现有网络基础上的虚拟智能网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、调度及内容分发等功能模块,使用户在请求所需访问的内容时能够就近获取,以此来降低网络拥塞,提高资源对用户的响应速度。
(2)不使用CDN的通信流程
- 向传统的DNS服务器请求域名解析。
- DNS服务器返回域名对应的服务器IP。
- 根据服务器IP请求服务器内容。
- 服务器返回响应资源。
(3)使用CDN的通信流程
- 客户端向传统的DNS服务器请求域名解析。
- 传统的DNS服务器将域名解析权交给了CNAME指向的专用DNS服务器,所以对用户输入域名的解析最终是在CDN专用的DNS服务器上完成的。
- CDN专用的DNS服务器将CDN负载均衡器的IP发给客户端。
- 浏览器会重新向CDN负载均衡器发起请求,经过对用户IP地址的距离、所请求资源内容的位置等的综合计算,返回给用户确定的缓存服务器IP地址。
- 浏览器最后对缓存服务器进行请求资源。
(4)静态资源适合使用CDN
静态资源指的是不需要网站业务服务器参与计算即可得到的资源,包括第三方库的JavaScript脚本文件、样式表文件以及图片等,这些文件的特点是访问频率高、承载流量大、但更新频次低,且不与业务有太多耦合。
如果是动态资源文件,比如依赖服务器端渲染得到的HTML页面,它需要借助服务器端的数据进行计算才能得到,所以这样的资源不适合存放在CDN缓存服务器上。
四、面试常见问题
1、强缓存涉及到哪些请求头?
涉及到expires和cache-control两个字段,expires是HTTP1.0协议中的,cache-control是HTTP/1.1协议的。
2、为什么现在不用expries用cache control?
答:因为基于expires的强制缓存对本地时间戳过于依赖,如果客户端本地的时间与服务器端的时间不同步,那么对缓存过期的判断可能就会出错。cache-control通过maxage=xxx秒的形式来控制响应资源的有效期,如此可以避免服务器端和客户端时间戳不同步的问题。
3、强缓存public private no-store no-catch区别?(Cache-Control有哪些属性?分别表示什么意思?)
- public:表示响应资源既可以被客户端缓存也可以被代理服务器缓存。
- private:表示响应资源只能被浏览器缓存,如果没有显式指定则默认是private
- no-store:表示禁止使用任何缓存,每次请求都需要服务器给与全新的响应。
- no-cache:表示使用协商缓存。每次请求不再去判断强制缓存是否过期,而是直接向服务器发送请求来验证缓存的有效性。
- max-age:表示服务器端告知客户端浏览器响应资源的过期时长。
- s-maxage:表示缓存在代理服务器中的过期时长,且仅当设置了public属性值时才是有效的。
4、协商缓存的校验是在客户端还是服务器端?协商缓存怎么验证是否命中?
答:协商缓存的校验是服务器端。
命中协商缓存:服务器端会对比文件最后的修改时间和客户端请求携带的时间是否一致,一致则判断命中缓存。
协商缓存存在两种形式:
-
一种是基于
last-modified,客户端第一次请求目标资源的时候,服务器返回的响应标头中包含last-modified和该资源的最后一次修改的时间戳,以及cache-control:no-cache,当客户端再次请求该资源的时候,会携带一个if-modified-since字段,如果这个字段对应的时间和目标资源的时间戳进行对比,没有变化则返回304状态码。 -
另一种是基于
Etag的协商缓存,手下服务端将要返回给客户端的数据通过etag模块进行哈希计算生成一个字符串,这个字符串类似于文件指纹,检测客户端的请求标头中的if-None-Match字段的值和第一步计算的值是否一致,一致则返回304,不一致则返回最新的数据以及etag标头和Cache-Control:no-cache。
5、协商缓存出于什么原因有Last-Modified,Etag?
答:之所以有last-modified还有etag,是因为这二者均有自己的不足,last-modified是根据请求资源的最后修改时间戳来进行判断的,有可能只是对文件名进行了编辑,但是文件内容并未修改,这样时间戳也会更新,从而导致协商缓存判断失效,请求了已经存在的完整资源,这对网络带宽是一种浪费,也有可能是文件修改的速度是毫秒级别的,但是last-modified的单位是秒,可能无法识别出资源的修改。etag并非last-modified的完全替代方案,只能是一种补充方案,etag存在的问题是,服务器需要对文件资源进行etag计算,需要付出额外的计算开销,如果资源的尺寸比较大,生成Etag的过程可能会影响服务器的性能,所以这也就是为什么协商缓存既有last-modified又有etag的原因了。
6、协商缓存和强缓存的区别?
相同点:都是从客户端缓存中读取资源。
不同点:
- 如果浏览器命中的是强缓存,则不需要给服务器发请求,而协商缓存最终由服务器来决定是否使用缓存,即客户端与服务器之间存在一次通信。
- 在chrome中命中缓存,返回的状态码是200,而如果是协商缓存,返回的是状态码304。
7、expires 和 cache-control 哪个优先级高? 不缓存怎么设置?
- expires是HTTP/1.0的产物
- Cache-Control则是HTTP/1.1的产物
- 二者如果同时存在的话,Cache-Control优先级比Expires高。
- 不缓存则是通过Cache-Control:no-store设置。
8、LastModified 对应有个请求头是什么?
last-modified-since
9、缓存的优先级顺序?
Cache-Control > Expires > Etag > Last-Modified
10、缓存更新怎么办?
现在突然来一个需求,需要将h1的字体颜色修改为红色。我将index.css修改了,但是在访问网站时候并没有看到想看的效果,字体还是蓝色,因为除了html文件,其余资源使用的是强缓存,所以每次访问都是访问强缓存里面的资源(强缓存没过期期间),得强制刷新才能跳过缓存重新请求拿到最新的文件。 这样显然是不合理,那么该如何做呢? 之前html不是设置了协商缓存嘛,所以每次访问都会询问html文件是否是最新的,所以只要修改html文件里面的css引入地址就行了 比如:在后面加个版本号,因为每次html都会发送请求询问是否过期,所以就可以达到效果了。 这样确实可行,但是开发不可能就引用一个css文件,往往是多个的,我每次修改一个css文件,其余的版本也要跟着升级但其余的css根本没有改动啊,所以这种方式就不大行,只适用于这种简单的网站应用。
具体可参考:前端静态资源缓存与更新
11、后端怎么设置缓存?
如果需要浏览器强缓存,我们可以这样设置:
res.setHeader('Cache-Control', 'public, max-age=xxx');
如果需要协商缓存,则可以这样设置:
res.setHeader('Cache-Control', 'public, max-age=0');
res.setHeader('Last-Modified', xxx);
res.setHeader('ETag', xxx);
12、怎么让浏览器不缓存静态资源
浏览器禁用缓存(打开控制台,勾选no-cache),用浏览器隐私模式打开页面
- 设置请求头: Cache-Control: no-cache, no-store, must-revalidate
- 给请求的资源带上版本号
<link rel="stylesheet" type="text/css" href="../css/style.css?version=1.8.9"/>
- 部分浏览器支持在HTML中禁用缓存
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/>
文章摘录自: