这是我参与更文挑战的第6天,活动详情查看:更文挑战
浏览器对于请求的处理方式:(优先级从上到下)
1. Service Worker
Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。
Service Worker 实现缓存功能一般分为三个步骤:首先需要先注册 Service Worker,然后监听到 install 事件以后就可以缓存需要的文件,那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。
当 Service Worker 没有命中缓存的时候,我们需要去调用 fetch 函数获取数据。也就是说,如果我们没有在 Service Worker 命中缓存的话,会根据缓存查找优先级去查找数据。但是不管我们是从 Memory Cache 中还是从网络请求中获取的数据,浏览器都会显示我们是从 Service Worker 中获取的内容。
2. Memory Cache
在浏览器的请求中,会经常看到上图的状态,from memory cache
.
理论上来说,所有浏览器请求的资源都会被储存在内存(memory cache)中,但是由于内存空间有限,所以只会做短期存放,通常在浏览器关闭后,内存中缓存的资源就会被释放掉。特殊情况下(例如单个页面占用过高内存),可能存在浏览器还未关闭缓存资源就被释放掉的情况。
Memory cache 的机制保证了同一个页面内的相同请求,实际只会被请求一次。例如同一张图片多次出现,只会被请求一次。但如果勾选了浏览器的Disable Cache
,则会每次都去请求服务器资源。
如果想要资源不进入memory cache,使用 max-age=0, no-cache
等配置是不生效的,需要使用no-store
来强制不缓存。
3. Disk Cache
Disk cache 也叫 HTTP cache,即存储在硬盘上的缓存,是实际存在于文件系统中的,并且运行跨会话和跨站点的情况下使用。
当浏览器关闭之后,缓存数据仍然存在,访问时仍会显示 from disk cache
。
虽然硬盘空间相对内存要大很多,但由于是长期存在的缓存,也不可能全盘接收,所以对于哪些资源需要缓存到硬盘,浏览器会严格根据HTTP 头中的信息来判断,对资源进行分类。如果命中缓存,则会从硬盘中读取资源。
Disk cache 也并非会始终增长,浏览器自动清理时,也会对一些最老的资源进行删除,具体的算法各个浏览器都有自己的策略。
生命周期 | 速度 | |
---|---|---|
Memory Cache | 内存(当前会话) | 快 |
Disk Cache | 硬盘(文件系统) | 相对慢 |
4. 网络请求
以上三种方式都没有找到缓存,浏览器会直接发送请求到服务器,请求资源。
同时会将请求到的资源,进行以下缓存处理,以备下次使用:
- 保留一份资源的引用在memory cache中
- 根据HTTP头字段,判断是否存入disk cache
- 根据Service Worker 中的handler 判断是否存入Cache Storage
Disk Cache
以上三种缓存中,最常用的是disk cache,也是跟HTTP请求相关度最高的缓存,所以也叫HTTP缓存。
在这种缓存方式中,又分为三步策略:
1. 强缓存
浏览器请求资源时,先访问缓存数据库寻找资源,如果存在直接返回。
判断字段:Cache-control > Expires
Expires
表示缓存到期时间的字段,是一个绝对时间:
Expires: Thu, 10 Nov 2017 08:45:11 GMT
如果某个资源设置了该字段,则在过期之前浏览器都不会再次请求。
由于是绝对时间,容易造成的问题是,如果改了本地时间,缓存判断就可能会失效。
Cache-Control
Cache-control
是表示资源缓存的一些具体时间或方式,也是平时应用比较广泛的一种方式。它和Expires的区别是,cache-control指定的时间是相对时间。
常用的值有:
max-age
最大有效时间,单位毫秒
private / public
private指只有客户端可以缓存,public则是包括客户端和代理服务器在内的所有内容都可以被缓存
no-cache
不需要缓存,但memory cache 不受该限制仍然会缓存
no-store
不需要缓存,memory cache 也不会缓存
must-revalidate
超过max-age的时间后,浏览器必须向服务器发送验证请求,验证资源是否有效
如果以上多个值同时存在,优先级如下:
2. 协商缓存
当浏览器端的强制缓存失效时,会带上缓存的标识去请求服务器,由服务器进行判断,如果该缓存未失效就返回状态码304告诉浏览器可以继续使用这个缓存,如果失效就返回新的资源和规则,这个过程叫做协商缓存。
协商缓存中,实际上仍然是发生了一次向服务端的请求,但是如果未失效情况下返回的仅为304状态码,不需要返回具体的内容,节省了一定的体积。
判断字段:Etag & If-None-Match
> Last-Modified & If-Modified-Since
Last-Modified & If-Modified-Since
服务器通过Last-Modified 告诉浏览器,资源上一次修改的时间。
浏览器将该资源和时间记录下来,下一次该资源请求进入到协商缓存阶段的时候,会把Last-Modified的值写入到If-Modified-Since 字段传给服务器,服务器对比后返回304或最新资源。
可能存在的问题:
- 精确度到秒,不支持秒以下的资源更新;
- 可能存在文件时间发生了变化,但内容没有变化的情况,无法被缓存。
Etag & If-None-Match
这两个字段是对上面一组字段的补充,Etag是一段hash字符串,作为文件的特殊标识,服务器不再根据时间来判断,而是根据文件版本来判断。也就是说浏览器会带着上一次缓存下来的Etag作为If-None-Match的值去请求,服务器判断Etag是否一致,来返回304或新资源。
这个方法一来解决了时间精度的问题,二来只关心文件版本的变化,不关心时间是否更新。
3. 直接获取服务器资源
最后一步,字面意思,直接请求服务器资源。