浏览器缓存

 

为什么第二次打开页面会快很多?

怎么让刷新或关闭浏览器之后数据依然不被清空?

 

主要是因为第一次加载页面过程中,缓存了一些数据,之后再加载就直接从缓存中获取而不用请求服务器,所以速度更快,也减轻了服务器的压力

网络方面的缓存分为三块:DNS缓存HTTP缓存CDN缓存,也有人把这里的 HTTP 缓存称为浏览器缓存

还有本地的就是:浏览器的本地存储离线存储,更快提高首屏加载速度,让页面飞起

 

DNS缓存

进入页面的时候会进行DNS查询,找到域名对应的服务器的IP地址,再发送请求

DNS域名查找先在客户端进行递归查询,如图

在任何一步找到就会结束查找流程,而整个过程客户端只发出一次查询请求

如果都没有找到,就会走DNS服务器设置的转发器,如果没设置转发模式,则向13根(13根: 全球共有13个根域服务器IP地址)发起解析请求

 

HTTP缓存

将http请求获取的页面资源存储在本地,之后再加载直接从缓存中获取而不用请求服务器,从而响应更快。先看图:

1625202449441.jpg

强缓存

第一次请求时,服务器把资源的过期时间通过响应头中的ExpiresCache-Control两个字段告诉浏览器,之后再请求这个资源的话,会判断有没有过期,没有过期就直接拿来用,不向服务器发起请求,这就是强缓存

 

Expires

用来指定资源到期绝对时间,服务器响应时,添加在响应头中。

[info]expires: Wed, 22 Nov 2021 08:41:00 GMT[/info]

 

Cache-Control

指定资源过期时间秒,如下,表示在这个请求正确返回后的300秒内,资源可以使用,否则过期

[info]cache-control:max-age=300[/info]

 

为什么指定缓存过期时间需要两个字段呢?

因为有的浏览器只认识 Cache-Control,有的浏览器不认识,不认识的情况下再找 Expires

 

Expires 和 Cache-Control 的区别

Expires 是HTTP/1.0中的,Cache-Control 是HTTP/1.1中的;

Expires 是为了兼容,在不支持 HTTP/1.1 的情况下才会发生作用

两者同时存在的话 Cache-Control 优先级高于 Expires;

 

Cache-Control请求头常见属性

字段(单位秒) 说明
max-age=300  拒绝接受长于300秒的资源,为0时表示获取最新资源
max-stale=100   缓存过期之后的100秒内,依然拿来用
no-cache   跳过当前的强缓存,发送HTTP请求,即直接进入协商缓存阶段

no-store      非常粗暴,不进行任何形式的缓存。

Cache-Control响应头常见属性

max-age=300    缓存有效期300秒
public    可以被任何终端缓存,包括代理服务器、CDN等
private   只能被用户的浏览器终端缓存(私有缓存)
   

 

强缓存的缺点

就是缓存过期之后,不管资源有没有变化,都会重新发起请求,重新获取资源

而我们希望的是在资源文件没有更新的情况下,即使过期了也不重新获取资源,继续使用旧资源

所以协商缓存它来了,在强缓存过期的情况下,再走协商缓存的流程,判断文件有没有更新

 

协商缓存

第一次请求资源时,服务器除了会返回给浏览器上面说的过期时间,还会在响应头添加 Last-Modified 字段,告诉浏览器该资源的最后修改时间

[info]last-modified: Fri, 27 Oct 2021 08:35:57 GMT[/info]

然后浏览器再次请求的时候就把这个时间再通过另一个字段If-Modified-Since,发送给服务器

[info]if-modified-since: Fri, 27 Oct 2021 08:35:57 GMT[/info]

服务器再把这两个字段的时间对比,如果是一样的,就说明文件没有被更新过,就返回状态码304和空响应体给浏览器,浏览器直接拿过期了的资源继续使用即可;如果对比不一样说明资源有更新,就返回状态码200和新的资源,如图

1625218343262.jpg

所以说Last-Modified/If-Modified-Since它俩是成对的,是为了对比文件修改时间

 

缺点

如果本地打开了缓存文件,即使没有对文件进行修改,但还是会造成Last-Modified被修改,服务器端不能命中缓存导致发送相同资源

如果资源有周期性变化,如资源修改后,在一个周期内又改回了原来的样子,我们认为这个周期前的缓存是可以使用的,但是Last-Modified不这样认为

 

因为这些缺点,所以便有了另外一对 ETag/If-None-Match,用来对比文件内容

 

ETag/If-None-Match

第一次请求资源时,服务器除了会在响应头上返回ExpiresCache-ControlLast-Modified,还在返回Etag字段,表示当前资源文件的一个唯一标识。这个标识符由服务器基于文件内容编码生成,能精准感知文件的变化,只要文件内容不同,ETag就会重新生成
 

[info]etag: W/"132489-1627839023000"[/info]

然后浏览器再次请求的时候就把这个文件标识 再通过另一个字段 If-None-Match,发送给服务器

[info]if-none-match: W/"132489-1627839023000"[/info]

服务器再把这两个字段对比,如果发现是一样的,就说明文件没有被更新过,就返回状态码304和空响应体给浏览器,浏览器直接拿过期了的资源继续使用;如果对比不一样说明资源有更新,就返回状态码200和新的资源

 

Last-Modified 和 ETag 的区别

Etag 感知文件精准度要高于 Last-Modified

同时使用时,服务器校验优先级 Etag/If-None-Match

Last-Modified 性能上要优于 Etag,因为 Etag 生成过程中需要服务器付出额外开销,会影响服务器端的性能

 

强缓存与协商缓存的区别

优先查找强缓存,没有命中再查找协商缓存

强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,资源是否有更新,服务器肯定知道

目前项目大多数使用缓存文案

1.协商缓存一般存储:HTML

2.强缓存一般存储:cssimagejs,文件名带上 hash

 

缓存实际使用策略

对于频繁变动的资源

使用Cache-Control:no-cache,使浏览器每次都请求数据,然后配合EtagLast-Modified来验证资源是否有效,这样虽然不能节省请求数量,但能显著减少响应数据大小

 

对于不常变化的资源

可以给它们的Cache-Control配置一个很大的max-age=31536000(一年),这样浏览器之后请求相同的URL会命中强缓存

 

缓存存放位置,和读取的优先级

强缓存命中或者协商缓存中服务器返回304的时候,我们直接从缓存中获取资源。那这些资源究竟缓存在什么位置呢?

 

1. Service Worker

可以把 Service Worker 理解为一个介于客户端和服务器之间的一个代理服务器。在 Service Worker 中我们可以做很多事情,比如拦截客户端的请求、向客户端发送消息、向服务器发起请求等等,其中最重要的作用之一就是离线资源缓存。

 

2. Memory Cache(内存)

就是将资源存储在内存中,下次访问直接从内存中读取。例如刷新页面时,很多数据都是来自于内存缓存。一般存储脚本、字体、图片。

优点是读取速度快;缺点由于一旦关闭Tab标签页,内存中的缓存也就释放了,所以容量和存储时效上差些

 

3. Disk Cache(硬盘)

将资源存储在硬盘中,下次访问时直接从硬盘中读取。它会根据请求头中的字段判断哪些资源需要缓存,哪些资源可以不请求直接使用,哪些资源已经过期需要重新请求。

优点是缓存在硬盘中,容量大,并且存储时效性更长;缺点是读取速度慢些

 

4. Push Cache

 

 

CDN缓存

当我们发送一个请求时,浏览器本地缓存失效的情况下,CDN会帮我们去计算哪得到这些内容的路径短而且快。

比如在广州请求广州的服务器就比请求新疆的服务器响应速度快得多,然后向最近的CDN节点请求数据

CDN会判断缓存数据是否过期,如果没有过期,则直接将缓存数据返回给客户端,从而加快了响应速度。如果CDN判断缓存过期,就会向服务器发出回源请求,从服务器拉取最新数据,更新本地缓存,并将最新数据返回给客户端。

 

几种刷新和回车的区别

使用 Ctrl+F5 强制刷新页面时,会对本地缓存文件直接过期,然后跳过强缓存和协商缓存,直接请求服务器

点击刷新或 F5 刷新页面时,对本地缓存文件过期,然后带If-Modifed-SinceIf-None-Match发起协商缓存验证新鲜度

浏览器输入URL回车,浏览器查找 Disk Cache(硬盘),有则使用,没有则发送网络请求

 

本地存储

Cookie

详情见以下链接

Cookie,Session,Token

 

最早被提出来的本地存储方式,在每一次 http 请求携带 Cookie,可以判断多个请求是不是同一个用户发起的,特点是:

有安全问题,如果被拦截,就可以获得 Session 所有信息,然后将 Cookie 转发就能达到目的。

跨域名不能共享Cookie

每个域名下的Cookie不能超过20个,大小不能超过4kb

Cookie在请求新页面的时候都会被发送过去

 

 

LocaStorage

是H5的新特性,是将信息存储到本地,它的存储大小比 Cookie 大得多,有5M,而且是永久存储,除非主动清理,不然会一直存在

 

受到同源策略限制,就是端口、协议、主机地址有任何一样不同都不能访问,还有在浏览器设为隐私模式下,也不能读取 LocalStorage

 

它的使用场景就很多了,比如存储网站主题、存储用户信息、等等,存数数据量多或者不怎么改变的数据都可以用它

 

接口封装。通过localStorage暴露在全局,并通过它的 setItem 和 getItem等方法进行操作,非常方便

SessionStorage

SessionStorage 也是H5新特性,也是5M,主要用于临时保存同一窗口或标签页的数据,刷新页面时不会删除,但是关闭窗口或标签页之后就会删除这些数据

 

SessionStorage 和 LocalStorage 一样是在本地存储,而且都不能被爬虫爬取,并且都有同源策略的限制,只不过 SessionStorage 更加严格,只有在同一浏览器的同一窗口下才能共享

 

它的使用场景一般是具有时效性的,比如存储一些网站的游客登录信息,还有临时的浏览记录等

 

 

离线存储

Service Worker

Service Worker是运行js主线程之外的,在浏览器背后的独立线程,自然也无法访问DOM,它相当于一个代理服务器,可以拦截用户发出的请求,修改请求或者直接向用户发出回应,不用联系服务器。比如加载JS和图片,这就让我们可以在离线的情况下使用网络应用

 

一般用于离线缓存(提高首屏加载速度)、消息推送网络代理等功能。使用Service Worker的话必须使用https协议,因为Service Worker中涉及到请求拦截,需要https保障安全

 

参考

 

浏览器工作原理与实践

阮一峰 Web API 教程

winty

为什么第二次打开页面快?五步吃透前端缓存,让页面飞起

 

 

阅读剩余
THE END