Open BetaSu opened 2 years ago
强缓存:根据服务器响应头字段(Expires或Cache-Control)的过期时间,来判断是否需要发送HTTP请求或者读取缓存数据的一种策略; 协商缓存:当强缓存失效之后,浏览器在请求头中携带相应的缓存tag(Last-Modified 或 ETag)来向服务器发请求,由服务器根据这个tag,来决定是否使用缓存;
Expires :即过期时间,存在于服务端返回的响应头中,告诉浏览器在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求;
Cache-Control:采用过期时长来控制缓存而非具体的过期时间,对应的字段有
Cache-Control:max-age=3600
,表示这个响应返回后在 3600 秒,也就是一个小时之内可以直接使用缓存max-age
差不多,但是区别在于s-maxage是针对代理服务器的缓存时间在HTTP/1.0和HTTP/1.1当中,这个字段是不一样的。在早期,也就是HTTP/1.0时期,使用的是Expires,而HTTP/1.1使用的是Cache-Control
Last-Modified: 即最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。
If-Modified-Since
字段;ETag: 服务器根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。
If-None-Match
这个字段的内容,并放到请求头中,然后发给服务器F5 刷新网页会让浏览器跳过检查强缓存,直接去服务器检查协商缓存,如果命中则Status Code会显示304 Not Modified
Ctrl + F5 强制刷新网页会导致浏览器直接跳过强缓存跟协商缓存,直接去请求新的资源,返回状态码200 OK
。
缓存(Brower Caching)是指在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,就可以直接从本地磁盘加载文档。在前端中,缓存可以可分为两个大类:
HTTP 缓存按照失效策略可分为:
强缓存不明思议,字面意思“强制”,只要命中,则不需要给服务器发请求。
HTTP/1.0 定义的强缓存字段,其给出了即在此时间之后,响应资源过期。
Expires: Fri Oct 22 2021 16:47:08 GMT+0800 (GMT+08:00)
设置过期时间,在过期时间内没如果命中,读取缓存数据,不再请求服务器资源。
但是由于 Expires 设置的过期时间是一个绝对时间,所有会受客户端时间的影响而变得不准确。比如手动修改客户端的时间让缓存失效或者永久失效等。
HTTP/1.1定义的强缓存字段,可以组合使用多种指令(多个指令之间可以通过 “,” 分隔)
强缓存生成过程
- 浏览器->浏览器缓存:发生 http 请求,询问是否存在浏览器缓存。
- 浏览器缓存 ->浏览器 :没有请求资源的缓存数据。
- 浏览器 -> 服务器:发生请求,或者最新的资源数据。
- 服务器 -> 浏览器:返回资源和缓存标识。
- 浏览器 -> 浏览器缓存: 根据缓存标识,进行资源缓存。
强缓存生效过程
- 浏览器 -> 浏览器缓存:发生请求,最开始会查询浏览器缓存是否有浏览器缓存。
- 浏览器缓存 -> 浏览器:有缓存资源,并且没有失效,将缓存给到浏览器。
向服务器发送请求,服务器会根据这个请求的 request header 的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
Last-Modified 资源的最后更新时间,当浏览器请求服务器资源,在响应头中设置 Last-Modified,浏览器会将拿到的 Last-Modified 存储起来。当浏览器再次访问该资源时会设置 If-Modified-Sine( = Last-Modified),放入请求头,发送到服务器。服务器会根据资源的更新情况进行判断是否需要返回新的资源,返回新的资源,状态码200,返回新的 Last-Modified。资源没有更新,返回状态码304,返回旧的 Last-Modified。
但是 Last-Modified 也有自己的弊端。它的最小但是是秒,试想一下,如果服务器资源的修改资源的速度非常的快,快到毫秒级别,那么服务器会误以为资源是没有被修改的,导致浏览器获取不到最新的资源。还有另外一种情况就是服务器资源是被修改过了,但是资源的内容没有改变,这种情况服务器会重新设置 Last-Modified,当浏览器请求资源携带 If-Modified-Sine,服务器进行If-Modified-Sine 和 Last-Modified 进行对比时,会发现是不同,从新加载资源。
Etag 是服务器给资源打上的一个标记。当浏览器请求服务器资源,在响应头设置 Etag ,浏览器拿到这个 Etag,会将它存储起来,当再次请求访问该资源是,会在请求头上设置 If-None-Match (= Etag),放入请求头,发生到服务器,服务器会根据资源的更新情况进行判断是否需要返回新的资源,返回新的资源,状态码200,返回新的 Etag。资源没有更新,返回状态码304,返回旧的 Etag。
相对于 Last-Modified,Etag 到底由撒优势了?这需要从 Etag 的生成来说起。 Etag 的生成一般有两种情况:
缓存新鲜度
这里可以在随带说一下缓存新鲜度。 缓存新鲜度意为指明缓存是否新鲜,简单来说缓存是否在保质期,有么有过期。缓存是否新鲜取决于两个因素,缓存新鲜度(保质期多长)和缓存使用期(已经过去了多长时间)。
响应使用期 = max(age_value, max(response_time - date_value)) 传输延迟时间 = response_time - request_time 停留缓存时间 = now - response_time
缓存使用期:= 响应使用期 + 传输延迟时间 + 停留缓存时间 = max(age_value, max(response_time - date_value)) + now - request_time。
response_time:浏览器缓存收到响应的本地时间,客户端时间
date_value:响应首部的 date 值,服务器创建报文的时间
age_value:响应首部 age 值,源服务器在多久前创建了响应或者代理服务器存储的时长
request_time:浏览器缓存发起请求的本地时间,客户端时间r
now:客户端当前时间,客户端时间
因此一旦修改了电脑客户端本地时间为未来时间,缓存使用期的计算便会受到影响,主要是停留缓存时间会变大,从而导致缓存使用期超出缓存新鲜度范围(强缓存失效)。 这便是 max-age 仍然受到本地时间影响的原因所在。
但是这里就会有同学有一个疑问?缓存新鲜度:= max-age || (expires - date),如果没有 max-age(s-maxage) 和 expires 这两个关键的字段值时,强缓存的新鲜度如何计算?如果是这样的话,只能说计算不了,但是浏览器会触发启发式缓存。
启发式缓存 启发式缓存会有一套计算缓存新鲜度的公式。 缓存新鲜度 = max(0,(date - last-modified)) * 10%
当然如果 last-modified 也没有,那浏览器就会有任何的缓存,每一次请求都是请求最新的资源。
浏览器缓存按照缓存位置可分为:
按照存储类型可分为:
对于 memory cache、disk cache 来说也遵循访问的获取顺序:
并且针对不同的资源存储的方式也不太一样:
“正常重新加载”模式会优先读取缓存。
所有资源都重新向服务器获取,这个没有问题,但是检查下请求报头我们会发现,使用硬性重新加载后所有资源的请求首部都被加上了 cache-control: no-cache 和 pragma: no-cache,两者的作用都表示告知(代理)服务器不直接使用缓存,要求向源服务器发起请求,而 pragma 则是为了兼容 HTTP/1.0。 因此硬性重新加载并没有清空缓存,而是禁用缓存,其效果类似于在开发者工具 Network 面板勾选了 Disable cache 选项。
答:
对于强缓存,控制它的字段分别是:Expires和Cache-Control,其中Cache-Control优先级比Expires高。当客户端发出一个请求到服务器,服务器希望你把资源缓存起来,于是在响应头中加入了这些内容
Cache-Control: max-age=3600 我希望你把这个资源缓存起来,缓存时间是3600秒(1小时)
Expires: Thu, 10 Nov 2020 08:45:11 GMT 到达指定时间过期
Date: Thu, 30 Apr 2020 12:39:56 GMT
Etag:W/"121-171ca289ebf",(后面协商缓存内容)这个资源的编号是W/"121-171ca289ebf"
Last-Modified:Thu, 30 Apr 2020 08:16:31 GMT,(后面协商缓存内容)这个资源的上一次修改时间
Cache-Control和 Expires分别是HTTP/1.1 和 HTTP/1.0的内容,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段我们都会设置。 浏览器收到这个响应之后就会做下面的事情
浏览器把这次请求得到的响应体缓存到本地文件中 浏览器标记这次请求的请求方法和请求路径 浏览器标记这次缓存的时间是3600秒 浏览器记录服务器的响应时间是格林威治时间2020-04-30 12:39:56
这一次的记录非常重要,它为以后浏览器要不要去请求服务器提供了依据。 之后当客户端收准备再次请求同样的地址时,它突然想起了一件事:我需要的东西在不在缓存里呢? 此时,客户端会到缓存中去寻找是否有缓存的资源,如下
判断缓存是否有效就是通过把max-age + Date,得到一个过期时间,看看这个过期时间是否大于当前时间,如果是,则表示缓存还没有过期,仍然有效,如果不是,则表示缓存失效。
一旦发现缓存无效,它并不会简单的把缓存删除,而是抱着一丝希望,想问问服务器,我这个缓存还能继续使用吗? 于是,浏览器向服务器发出了一个带缓存的请求 所谓带缓存的请求,无非就是加入了以下的请求头:
If-Modified-Since: Thu, 30 Apr 2020 08:16:31 GMT 亲,你曾经告诉我,这个资源的上一次修改时间是格林威治时间2020-04-30 08:16:31,请问这个资源在这个时间之后有发生变动吗?
If-None-Match: W/"121-171ca289ebf" 亲,你曾经告诉我,这个资源的编号是W/"121-171ca289ebf,请问这个资源的编号发生变动了吗?
之所以要发两个信息,是为了兼容不同的服务器,因为有些服务器只认If-Modified-Since,有些服务器只认If-None-Match,有些服务器两个都认,但是一般来说 If-None-Match 的优先级高于 If-Modified-Since 此时可能会产生两个结果
缓存失效:那么非常简单,服务器再次给予一个正常的响应(响应码200 带响应体),同时可以附带上新的缓存指令,浏览器缓存新的内容 缓存有效:服务器返回304重定向,并且响应头带上新的缓存指令,浏览器作出相应缓存动作。
当浏览器再次访问一个已经访问过的资源时,它会这样做: 1.根据相关字段判断是否命中强缓存,如果命中,就直接使用缓存了。 2.如果没有命中强缓存,就发请求到服务器检查是否命中协商缓存。 3.如果命中协商缓存,服务器会返回 304 告诉浏览器使用本地缓存。 4.否则,返回最新的资源。
这是来自QQ邮箱的假期自动回复邮件。 您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
发生问题的场景
浏览器的缓存策略一般分为强缓存和协商缓存,你知道他们之间的区别吗?
需要解决的问题
请按照一下顺序回答:
1.什么是强缓存?什么是协商缓存? 2.与他们有关的请求/响应头字段有哪些?分别是什么含义? 3.从缓存角度回答 Ctrl + F5 强制刷新网页和 F5 刷新网页的区别。
最佳答案评选标准
最佳答案
悬赏中,欢迎作答...
答题同学须知
答题规范:请在
一次评论
中完成作答,后续修改也请编辑该评论,而不是追加新的评论评选标准:最佳答案由
围观同学
的 👍 和卡颂共同决定评选时间:一般是问题发布24小时后评选,如果问题发布当天回答数较少,问题悬赏金额可能增加,同时悬赏时间也会增加
围观同学须知
对于你满意的答案,请不要吝惜你的 👍,这是评选最佳答案的依据
非答题的评论
会被删除,问题相关讨论请在赏金猎人群中进行