Skip to content

缓存.png

浏览器缓存

强缓存

强缓存就是当我们访问URL的时候,不会向服务器发送请求,直接从缓存中读取资源,但是会返回200状态码。


如何设置强缓存? 我们第一次进入页面,请求服务器,然后服务器进行应答,浏览器会根据response Header来判断是否对资源进行缓存,如果响应头中expires或者cache-control字段,代表这是强缓存,浏览器就会把资源缓存在memory cache 或 disk cache中。

第二次请求时,浏览器会判断请求参数,如果附和强缓存条件就直接返回状态码200,从本地缓存中拿数据。否则,看是否符合协商缓存,符合就返回状态码304,不符合就去服务器取。


HTTP/1.0时期,使用的是ExpiresHTTP/1.1, 使用的是Cache-Control

Expires

Expires即过期时间,存在于服务端返回的响应头中,告诉浏览器在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。

expires: Thu, 01 Dec 2022 09:42:17 GMT
// 值为一个时间戳,准确来讲是格林尼治时间

缺点:**服务器时间和浏览器时间可能不一致。**它判断是否过期是用本地时间来判断的,本地时间是可以自己修改的。

Cache-Control

HTTP/1.1中控制缓存的字段。它与expires本质不同在于它没有采用具体的过期时间点这种方式,而是采用过期时长max-age来控制缓存。 当Expires和Cache-Control同时存在时,Cache-Control优先级更高。

cache-control: max-age = 6600 // 单位是秒 s
缓存请求指令

客户端可以在HTTP请求中使用的标准 Cache-Control 指令。

Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: only-if-cached
缓存响应指令

服务器可以在响应中使用的标准 Cache-Control 指令。

Cache-control: must-revalidate
Cache-control: no-cache
Cache-control: no-store
Cache-control: no-transform
Cache-control: public
Cache-control: private
Cache-control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-control: s-maxage=<seconds>
可缓存性指令:

public: 表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,CDN等等)缓存,即使是通常不可缓存的内容。(例如:1.该响应没有max-age指令或Expires消息头;2. 该响应对应的请求方法是 POST 。)


private 表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)。该响应只能应用于浏览器私有缓存中


no-store 缓存不应存储有关客户端请求或服务器响应的任何内容,即不使用任何缓存。


no-cache 每次请求发送时,缓存会将此请求发送到服务器,服务器端会验证请求中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓存副本。 强制要求缓存把请求提交给原始服务器进行验证(协商缓存验证)。


到期:

max-age=<seconds> 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)


重新验证:

must-revalidate 一旦资源过期(比如已经超过max-age),在成功向原始服务器验证之前,缓存不能用该资源响应后续请求。


Progma 这个是HTTP1.0中禁用网页缓存的字段,其取值为no-cache,和Cache-Controlno-cache效果一样


协商缓存

协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程。 这样的缓存标识分为两种

  1. Last-Modified / If-Modified-Since
  2. ETag / If-None-Match

Last-Modified / If-Modified-Since

Last-Modified是服务器响应请求时,在响应头中返回该资源文件在服务器最后被修改的时间。 浏览器接收到后,如果再次请求,会在请求头中携带If-Modified-Since字段,这个字段的值也就是上次请求返回的Last-Modified值。 服务器收到该请求,发现请求头含有If-Modified-Since字段,则会根据If-Modified-Since的字段值与该资源在服务器的最后被修改时间做对比,

  1. 如果请求头中If-Modified-Since的字段值 小于 服务器中资源的最后修改时间。说明资源更新了,则返回新的资源,状态码为200;
  2. 否则,返回304,告诉浏览器直接使用缓存文件。

ETag / If-None-Match

Etag是服务器响应请求时,根据当前文件的内容,给文件生成的唯一标识,只要里面的内容有改动,这个值就会变。 浏览器接收到ETag的值,会在下次请求时,将这个值作为If-None-Match这个字段的内容,并放到请求头中,然后发给服务器。 服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对:

  • 如果两者不一样,说明要更新了。返回新的资源,跟常规的HTTP请求响应的流程一样。
  • 否则返回304,告诉浏览器直接用缓存。

Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效

缓存位置

  1. Service Worker
  2. Memory Cache
  3. Disk Cache
  4. Push Cache

优先级从高到低

Service Worker

是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用Service Worker ,传输协议必须是HTTPS。 可以支持离线缓存、消息推送、网络代理等功能。其中的离线缓存就是Service Worker Cache Service Worker同时也是 PWA的重要实现机制。

Memory Cache

Memory Cache内存缓存。主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

Disk Cache

就是存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,但是他的优势在于存储容量和存储时长。 一般CSS文件会缓存到Disk Cache,JS会缓存到Memory Cache,Png看情况。 prefetch cache(预取缓存) link标签上带了prefetch,再次加载会出现。 prefetch是预加载的一种方式,被标记为prefetch的资源,将会被浏览器在空闲时间加载。

Push Cache

推送缓存,是 HTTP/2 中的内容,当以上三种缓存都没有命中时,才会被使用。它只会在会话中存在,一旦会话结束就被释放,并且缓存时间也很短。


总结

刷新F5

  1. Ctrl+F5 (Mac:cmd+shift+R)强刷新网页时,直接从服务器加载,跳过强缓存和协商缓存
  2. F5 (Mac: cmd+R)刷新网页时,跳过强缓存,但是会检查协商缓存
  3. 浏览器输入URL时,会检查缓存。

新鲜度

当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓存会先将此请求附加一个If-None-Match头,然后发给目标服务器,以此来检查该资源副本是否是依然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不会有带有实体信息),则表示此资源副本是新鲜的,这样一来,可以节省一些带宽。 若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带有该资源的实体内容返回。

参考

  1. 图解 HTTP 缓存
  2. 彻底理解浏览器的缓存机制
  3. 前端浏览器缓存知识梳理
  4. 实践这一次,彻底搞懂浏览器缓存机制