浏览器存储
cookie
HTML5新规范之前的浏览器数据存储方式,特点如下:
- 存储空间限制在4kB,常用于存储用户登录状态等精简数据;
- 存储数据需要经过encodeURIComponent和decodeURIComponent加密处理;
- 默认数据有效期在当前会话,关闭窗口数据丢失,需要手动设置expires有效期;
- 可以设置domain和path指定cookie访问限制;domain默认是当前域名,path是当前路径。如baidu.com/yunpan, domain=”baidu.com”,path=”/yunpan”;
- httponly设置为true时,cookie仅供http使用,JS无法获取cookie值;
- document并未提供cookie封装api,需要用户手动封装;
localstorge
HTML5新引入的浏览器本地数据存储策略,与cookie不同的是:
- localstorge可以存储更多的数据,存储空间提升到5MB;
- 且仅用于浏览器本地存储,不参与服务器之间的通信,也就是说http请求不会带上localstorge数据;
- 同一个浏览器内,同源文档(同域名)之间可以共享localstorge数据,即使浏览器中的不同标签页;
- window提供了完整的api封装,setItem,getItem,clear等
sessionstorage
用于存储浏览器当前窗口与服务端之间的会话数据,与localstorge不同的是:
- 窗口(或浏览器标签页)关闭,sessionstorage中的数据丢失;
- 也遵循同源文档之间数据共享,但是仅限于同一窗口,不能跨窗口。即只能在同一个浏览器的标签页内共享数据,如self和iframe。跨窗口(标签页)不能共享数据
indexDB
HTML5新规范提供的一种事务型数据库系统,类似于基于 SQL 的 RDBMS,由于目前浏览器支持率不高,这里不详述,有兴趣参考indexDB MDN文档
Application Cache
HTML5 提供的一种应用程序缓存机制,使得基于web的应用程序可以离线运行,该特性已经从 Web 标准中删除,逐渐被Service Worker替代
总结
存储方式 | 特点 |
---|---|
cookie | 不支持跨域,存储空间限制4kB,可通过设置domain和path实现共享域名,关闭窗口数据丢失,需手动设置expires有效期,httponly设置为true时,JS无法获取cookie值,仅供http使用 |
localstorge | 不支持跨域,单域名下存储空间限制5MB,仅供浏览器本地存储,不参与http请求,同域名下不同窗口可以共享数据,数据默认永久有效,除非手动清除 |
sessionstorage | 与localstorge类似,不同的是不能跨窗口(浏览器标签页)共享数据,只能在同域名同窗口内共享数据,且窗口关闭时会话数据丢失 |
indexDB | HTML5新规范,存储空间限制50MB,目前浏览器支持率不高 |
Application Cache | 已逐渐被Service Worker替代,PWA应用解决方案 |
http缓存
一般来说,浏览器只会对GET请求开启缓存。根据http缓存位置区分,可以分为4种:
- Service Worker:由一个manifest清单文件记录缓存了哪些文件资源;
- Memory Cache:内存中的缓存,存储资源有限,且会随着进程关闭而释放内存;
- Disk Cache:磁盘中的缓存,读写速度比Memory Cache慢。绝大部分的缓存都来自Disk Cache,可以在HTTP 的协议头中设置;
- Push Cache:http2.0主动推送资源缓存,当以上3个缓存都没有命中时,才会被启用
根据http缓存方式区分,可以分为强缓存和协商缓存
那么,http什么时候会对资源进行强缓存,什么时候会协商缓存呢?当我们发起一个http请求时,资源匹配又是怎样进行的呢?带着问题,我们先看看什么是强缓存和协商缓存
强缓存
在http响应头中,Expires 和 Cache-Control字段用来标记强缓存
Expires
Expires是http/1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间
Expires: Wed, 11 May 2018 07:20:00 GMT
复制代码
缓存原理:
- 浏览器第一次请求资源,服务器返回资源,并在 Response Header 中携带 Expires 属性;
- 浏览器在接收资源的同时,把资源和所有Response Header一起缓存下来;
- 浏览器再次请求这个资源时,先从缓存文件中查找,找到该资源后拿出 Response Header 中的 Expires与当前请求时间进行比较,如果请求时间在Expires之前,命中缓存资源;
- 如果第3步没有命中缓存,浏览器向服务器发起请求,服务器返回资源后更新缓存资源和Response Header;
缺点:Expires比较受限于本地时间,如果修改了本地时间,可能会造成缓存失效
Cache-Control
为了摒弃Expires受限于本地时间问题,http/1.1采用 Cache-Control 来标记,优先级高于 Expires,表示的是相对时间
Cache-Control: max-age=315360000
复制代码
Cache-Control还有一些其他值:
- no-cache:在与原始服务器进行新鲜度验证之前,缓存不能将其提供给客户端使用。简单来说就是每次使用缓存资源前,要对客户端进行重新验证;
- no-store:不缓存数据;
- public:可以被所有用户缓存(多用户共享),包括终端和CDN等中间代理服务器;
- private:只能被终端浏览器缓存(而且是私有缓存),不允许中继缓存服务器进行缓存。
缓存原理:
- 浏览器第一次请求资源,服务器返回资源,并在 Response Header 中携带 Cache-Control 属性;
- 浏览器在接收资源的同时,把资源和所有 Response Header 一起缓存下来;
- 浏览器再次请求这个资源时,先从缓存文件中查找,找到该资源后拿出 Response Header 中的 Cache-Control 和第一次请求的时间计算出一个资源过期时间,如果请求时间在过期时间之前,命中缓存资源;
- 如果第3步没有命中缓存,浏览器向服务器发起请求,服务器返回资源后更新缓存资源和 Response Header;
Cache-Control 记录的是一个相对时间,在进行时间计算的时候都用到本地时间,即两次资源请求前后的本地时间差大于 Cache-Control,资源过期,小于 Cache-Control 时命中缓存
协商缓存
如果浏览器对资源请求没有命中强缓存,就会向服务端发起请求,验证是否命中协商缓存。如果命中协商缓存,http返回304响应并且显示一个 Not Modified 字符串
协商缓存是利用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的
Last-Modified 和 If-Modified-Since
Last-Modified 表示资源文件最后修改日期,If-Modified-Since 资源文件上一次的修改时间
缓存原理:
- 浏览器第一次请求资源文件,服务器返回资源并在 Response Header 中返回 Last-Modified 字段,表示这个资源在服务器上的最后修改时间;
- 浏览器再次请求该资源(假设没有命中强缓存)时,在 Request Header 中带上 If-Modified-Since 字段,字段值就是上次服务器返回该资源时 Response Header 中的 Last-Modified 值;
- 服务器接收请求,比较请求头中的 If-Modified-Since 值和 Last-Modified 值判断两次请求期间资源是否发生变化;如果没有变化,返回 304 Not Modified,但是不返回资源内容;如果发生变化,返回资源内容;
- 浏览器接收返回,如果收到的是304返回,从缓存中读取资源;如果收到的是200返回,说明协商缓存没有命中,加载服务器返回的资源,并更新缓存中的资源和 Response Header 中的 Last-Modified 字段值
缺点:不能准确判断资源内容是否发生变化。假如只是资源文件属性发生变化,Last-Modified 比较结果也会导致协商缓存失效
ETag 和 If-None-Match
ETag 可以看成是资源文件的一个唯一标记,ETag 值与资源内容一一对应,也就是说只要资源文件内容没有发生改变,ETag 的值就是一样的;如果资源文件内容发生了变化,ETag 的值也会发生改变。ETag 优先级高于 Last-Modified,即 Response Header 中同时存在这两个字段时,以 ETag 为准
缓存原理:
- 浏览器第一次请求资源文件,服务器返回资源并在 Response Header 中返回 ETag 字段;
- 浏览器再次请求该资源(假设没有命中强缓存)时,在 Request Header 中带上 If-None-Match 字段,字段值就是上次服务器返回该资源时 Response Header 中的 ETag 值;
- 服务器接收请求,比较请求头中的 If-None-Match 值和 ETag 值判断两次请求期间资源是否发生变化;如果没有变化,返回304 Not Modified,但是不返回资源内容;如果发生变化,返回资源内容;
- 浏览器接收返回,如果收到的是304返回,从缓存中读取资源;与 Last-Modified 不同的是,不管是否命中协商缓存,都会用 Response Header 中的 ETag 值更新缓存中的 ETag 值。
ps:ETag 的生成过程也会增加服务器的额外开销,影响服务器性能。ETag不能完全替代 Last-Modified,只能看作是 Last-Modified 的加强和补充
最后借用一张图描述强缓存和协商缓存流程