HTTP缓存和浏览器的本地存储

11次阅读

共计 4147 个字符,预计需要花费 11 分钟才能阅读完成。

一、HTTP 缓存

http 请求做为影响前端性能极为重要的一环,因为请求受网络影响很大,如果网络很慢的情况下, 页面很可能会空白很久。对于 首次进入 网站的用户可能要通过优化接口性能和接口数量来解决。但是,对于 重复进入 页面的用户,除了浏览器缓存,http 缓存可以很大程度对已经加载过的页面进行优化。

1. 缓存位置

从缓存位置上来看,分为 4 种,从上往下依次检查是否命中,如果但都没有命中则重新发起请求。
Service Worker 是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker 的话,传输协议必须为 HTTPS。
Memory Cache 也就是内存中的缓存,主要包含的是当前中页面中已经抓取到的资源, 例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快, 内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。
内存缓存中有一块重要的缓存资源是 preloader 相关指令(例如 <link rel=”prefetch”>)下载的资源。它可以一边解析 js/css 文件,一边网络请求下一个资源。
Disk Cache 也就是存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
绝大部分的缓存都来自 Disk Cache,在 HTTP 的协议头中设置。
Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在 Chrome 浏览器中只有 5 分钟左右,同时它也并非严格执行 HTTP 头中的缓存指令。

2. 用户操作对缓存的影响

下面主要说一下前端优化能入手的地方,也就是 强缓存 协商缓存,并且缓存策略都是通过设置 HTTP Header 来实现的。

3. 强缓存

浏览器在第一次访问接口后的 response headers 里会携带一些字段,这些字段决定关于这个请求的缓存情况,
与强缓存相关的 header 字段有两个:

1、expires:过气网红,这是http1.0 时的规范;它的值为一个绝对时间的 GMT 格式的时间字符串,如 Mon, 10 Jun 2015 21:31:12 GMT,如果发送请求的时间在 expires 之前,那么本地缓存始终有效,否则就会发送请求到服务器来获取资源

2、cache-control:新星 :max-age=number,这是 http1.1 时出现的 header 信息,主要是利用该字段的max-age 值来进行判断,它是一个相对值;资源第一次的请求时间和 Cache-Control 设定的有效期,计算出一个资源过期时间,再拿这个过期时间跟当前的请求时间比较,如果请求时间在过期时间之前,就能命中缓存,否则就不行;
no-cache:不使用本地缓存。需要使用协商缓存,先与服务器确认返回的响应是否被更改,如果之前的响应中存在 ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。

no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。

public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。

private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
注意:如果 cache-control 与 expires 同时存在的话,cache-control 的优先级高于 expires

强缓存时段命中,会直接从缓存中返回数据,返回值 200;这一时间段,不管接口内容有没有变化都不会进行请求更新。

4. 协商缓存

当没有强缓存时,会向服务端寻求帮助,也就是问一下服务端有没有更改,向接口判断是否有缓存。如果命中协商缓存则返回 304 状态码,并且从本地返回缓存内容。如果没有命中,则重新发起请求。
协商缓存需要跟服务端通过特殊标示连接,即第一次请求的响应头带上某个字段(Last-Modified或者 Etag),则后续请求则会带上对应的请求字段(If-Modified-Since 或者If-None-Match),若响应头没有 Last-Modified 或者 Etag 字段,则请求头也不会有对应的字段。

具体过程如下:

Last-Modified/If-Modified-Since

1. 浏览器第一次跟服务器请求一个资源,respone 的 header 里加上 Last-Modified:表示这个资源在服务器上的 最后修改时间

2. 浏览器再次跟服务器请求这个资源时,在 request 的 header 上加上 If-Modified-Since 的 header:上一次请求时返回的 Last-Modified 的值

3. 服务器再次收到资源请求时,会判断 最后修改时间 是否有变化,如果没有变化则返回 304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容,Last-Modified 会被修改为最新的值。如果没有变化,服务器返回 304 Not Modified,Last-Modified 不会修改,response header 中不会再添加 Last-Modified 的 header

4. 浏览器收到 304 的响应后,就会从缓存中加载资源

Etag/If-None-Match

由服务器生成的 每个资源的唯一标识字符串,只要资源有变化就这个值就会改变;其判断过程与 Last-Modified/If-Modified-Since 类似,与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个ETag 返回,即使这个 ETag 跟之前的没有变化。

1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新 GET;

2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改,(比方说 1s 内修改了 N 次),If-Modified-Since 能检查到的粒度是 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME 只能精确到秒);

3. 某些服务器不能精确的得到文件的最后修改时间。

Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

二、浏览器本地存储

浏览器本地缓存最常用的是 cookie、localStroage、sessionStroage、webSql、indexDB。

1.cookie 使用

cookie 的用法很简单, 可以通过服务端设置,js 也可以通过 documnet.cookie=” 名称 = 值;”(不要忘记以; 分割)来设置。
cookie 的 字符串可以用 encodeURIComponent()来保证它不包含任何逗号、分号或空格 (cookie 值中禁止使用这些值).
cookie 一般用做为登陆态保存、密码、个人信息等关键信息保存使用,所以为了安全也是 遵守同源策略原则 的。
可以通过下面参数具体设置:
;path=path (例如 ‘/’, ‘/mydir’) 如果没有定义,默认为当前文档位置的路径。
;domain=domain (例如 ‘example.com’,‘subdomain.example.com’) 如果没有定义,默认为当前文档位置的路径的域名部分。与早期规范相反的是,在域名前面加 . 符将会被忽视,因为浏览器也许会拒绝设置这样的 cookie。如果指定了一个域,那么子域也包含在内。
;max-age=max-age-in-seconds (例如一年为 606024*365)
;expires=date-in-GMTString-format 如果没有定义,cookie 会在对话结束时过期这个值的格式参见 Date.toUTCString()
;secure (cookie 只通过 https 协议传输)
;HttpOnly 限制 web 页面程序的 browser 端 script 程序读取 cookie

缺点
容量有限制,不能超过 4kb
在请求头上带着数据安全性差

2.localStorage 和 sessionStorage 使用

html5 新增本地存储,localStorage 生命周期是永久,除非主动清除 localStorage 信息,否则这些信息将 永远存在 。存放数据大小为一般为 5MB,sessionStorage 仅在当前会话下有效,关闭页面或浏览器后被清除。而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。也是 遵守同源策略原则

// 1、保存数据到本地
// 第一个参数是保存的变量名,第二个是赋给变量的值
localStorage.setItem('key', 'value');
// 复杂类型储存需要 ** 利用 JSON.stringify** 将对象转换成字符串;// 利用 **JSON.parse** 将字符串转换成对象
// 2、从本地存储获取数据
localStorage.getItem('key');
// 3、从本地存储删除某个已保存的数据
localStorage.removeItem('key');
// 4、清除所有保存的数据
localStorage.clear();

3. Web SQL

WebSQL 是前端的一个独立模块,是 web 存储方式的一种,我们调试的时候会经常看到,只是一般很少使用。并且,当前只有谷歌支持,ie 和火狐均不支持。
主要方法:

1.openDatabase:这个方法使用现有的数据库或者新建的数据库创建一个数据库对象。
2.transaction:这个方法让我们能够控制一个事务,以及基于这种情况执行提交或者回滚。
3.executeSql:这个方法用于执行实际的 SQL 查询。

4.indexDB

IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
具体概念 参考:参考文章

正文完
 0