大家好,我是林一一,这是一篇关于浏览器 缓存原理 和 本地存储 的文章,后续回持续推出关于,浏览器原理的文章。
一、浏览器的缓存篇
思维导图
所谓浏览器的缓存,就是浏览器通过
HTTP请求网络资源后将资源留在本地的一种行为。在页面上点击返回和前进的按钮就是利用浏览器的缓存。
- 浏览器的缓存分为两种
强缓存和协商缓存。 - 浏览器缓存资源的位置放置四个地方
Service Worker, Memory Cache, Disk Cache, Push Cache。Service Worker优先级最高到Push Cache。
浏览器请求资源过程
先本地再服务器(先强缓存再协商缓存)
- 浏览器请求资源时会先去判断本地缓存资源的
header是否有命中强缓存,如果命中强缓存则直接请求本地的资源,不向服务器发送请求。 - 如果没有命中强缓存或强缓存失效以后就会发送
HTTP请求服务器,这个过程采用的就是协商缓存
简单的说浏览器的缓存请求分为有无
HTTP请求两种。
强缓存
所谓的强缓存是我们没有向服务器发送
HTTP请求,而是直接从本地缓存中获取资源的一种行为。成功后返回状态码 200。
- 浏览器是根据响应头的
headers字段判断Expires/http1.0,Cache-Control/http1.1,来执行强缓存的过程。 - 没有或失效的强缓存,浏览器会向服务器发送请求资源。
Expires
http1.0 中一个页面的缓存字段,是一个格林时间。这个时间是浏览器强缓存资源失效的时间
Expires: Wed, 22 Nov 2021 08:41:00 GMT
上面的表示缓存的资源会在
2021年11月22号8点41分过期。
- 缺点:浏览器是根据本地的时间判断资源是否过期的,但是本地的时间可以被修改,所以在
HTTP1.1时Expires被放弃了。 - 缺点:假设浏览器端缓存的资源文件时间过期了,但是服务端的资源没有更新,那么浏览器去请求资源时就相当于浪费了带宽和时间
Cache-Control
HTTP1.1 中页面的缓存字段。 如果
Expires和Cache-Control都存在,那么Cache-Control的优先级更高。
Cache-Control的属性值有很多,其中属性max-age表示,一个相对的缓存时间
Cache-Control: max-age = 3600
表示距离上次请求的一小时内可以直接使用本地的缓存。不需要再次请求。
- 属性
public表示可以被浏览器或代理服务器缓存。 - 属性
private表示只能被浏览器缓存。 - 属性
no-cache跳过当前的强缓存,发送HTTP请求交给源服务器验证资源有效性,即直接进入协商缓存阶段,这是协商缓存的认证。协商缓存有效就返回 304 - 属性
no-store表示禁止使用缓存,每一次都需要请求服务器。
协商缓存
所谓协商缓存是指:浏览器携带
缓存的标识 tag向服务器发送请求,服务器更具携带过来的标识判断是否使用缓存的这个过程就是协商缓存。
- 浏览器请求服务器返回的结果有两种,一种
304表示服务器的资源还没有更新直接使用浏览器本地的缓存即可。另一种返回200,表示服务器资源更新且携带新的资源返回给浏览器。 - 缓存标识
tag分成两种Last-Modified/If-Modified-Since和ETag/If-None-Match,Etag / If-None-Match的优先级高于Last-Modified。
Etag / If-None-Match
- Etag 时服务器响应请求时 返回的一个唯一标识。这个标识只能由服务器产生。
etag: W/"5357d2b3f63545926812b95658505315"
- If-None-Match 时浏览器再次请求服务器时,会携带
Etag标识值发送给服务器,服务器会将这个值和在服务器中的Etag比较,两个值相等那么返回304,如果不相等就返回200将新的资源返回。
Last-Modified/If-Modified-Since
- Last-Modified,指的是返回请求的资源文件最后在服务器被修改的时间。
Last-Modified: Wed, 23 Nov 2021 08:41:00 GMT
-
If-Modified-Since,是浏览器再次请求资源时,会携带上一次返回的
Last-Modified的时间发送给服务器。服务器将上一次最后修改的时间 和现在的最后修改的时间做对比。如果大于If-Modified-Since的值,服务器就会返回新的资源 200,否则返回304。 -
Last-Modified 缺点:假设浏览器端缓存的资源文件时间过期了,但是服务端的资源没有更新,那么浏览器去请求资源时就相当于浪费了带宽和时间
-
Last-Modified 缺点:时间精度自能精确到s,假设一个文件在单位s之内被多次修改过,那么最新的修改文件将不能准确获取。
缓存位置
上面提到过缓存的位置
Service Worker, Memory Cache, Disk Cache, Push Cache。Service Worker优先级最高到Push Cache
- Service Worker 运行在浏览器的独立线程可以实现浏览器的缓存功能,传输协议需要使用
HTTPS。 - Memory Cache 是将资源缓存在内存中。
- Disk Cache 是将资源缓存在磁盘中
- Push Cache(推送缓存)是 HTTP/2 中,存活在会话
session中,存活的时间很短。
二、浏览器的本地存储篇
浏览器的本地缓存主要分为 5 种,
localStorage, sessionStorage, cookie, WebSql, indexedDB。
Cookie
cookie 由服务端生成。cookie 就是一个存放在客户端的一个小文件,也可以存放在本地,假如浏览器关闭后, cookie 也依旧存在
cookie 的设置过程
- 客户端向服务器发送一个 HTTP 请求。
- 服务器接收到请求后在响应头添加一个
set-cookie的字段 - 客户端接收到服务器的响应后将 cookie 保存下来,保存到本地的文件夹内
- 之后浏览器每一次请求都会携带 cookie 发送给服务器(耗性能)
- Cookie 的某一些属性
- Name:就是 cookie 的属性名
- Value:cookie 的属性值,需要做编码处理
- Expire:设置 cookie 的过期时间,Set-Cookie:Expires=Wed, 21 Oct 2015 07:28:00 GMT; 需要注意的是如果 cookie 的 Expire 没有设置,那么表示这个 cookie 是会话 cookie 浏览器关闭后就消失了。持久性的 cookie 是存放在硬盘中的,直到时间过期或者手动清除
- max-age:表示 cookie 失效之前的秒数,
Set-Cookie:Max-Age=604800;这个属性的值可以是正数:表示持久性的 cookie。负数:表示会话的 cookie 浏览器关闭就消失。0:表示立即删除这个cookie。当 Max-Age 和 Expire 都存在是,Max-Age 的优先级更高 - size:cookie 的大小,超过 4kB 后会被忽略。
- Domain: 记录域名信息, 但是不能跨站点设置域名,不会起作用
- path:
Path属性指定浏览器发出 HTTP 请求时,哪些路径要附带这个 Cookie。 - SameSite:限制第三方对 cookie 的携带请求,这属性可以防止 CSRF 攻击。三个重要的属性 strict: 禁止第三方请求携带 cookie。Lax:允许部分第三方携带 cookie 值。None 无论是否跨站都会发送 Cookie。一开始默认值是 None,后来默认值是 Lax。
- HttpOnly: 限定 cookie 只能通过 HTTP 传输,JavaScript 不能读取,防止 XSS 攻击
- Secure:限定了只有 HTTPS 才可以传输 cookie
如果不给cookie设置过期时间,会默认在会话结束后过期,浏览器关闭时过期。
-
优点:
- 记录用户的操作状态,密码等
- 弥补了 HTTP 的无状态
-
缺点:
- 容量小只有 4kb
- 不安全,可以随意修改 cookie 内容
- 耗费性能,每一次请求都会携带完整的 cookie
关于 SameSite 的属性请求
从上面可以看到 Lax 只允许部分的 get 请求携带 cookie,像页面中不同站点的 link标签,a标签中 href对应的站点。
localStorage
localStorage存值的方式和 cookie 类似,都会存放在同一个域名下,localStorage 可以长期存储,没有时间的限制。可以通过localStorage.setItem()/getItem()存取值。
- localStorage 优点:1.扩展了 cookie 的存储大小,可以存放 5M 大小,不同浏览器不同;2.只存储在浏览器不会和服务器之间有通信解决了cookie 的安全问题和性能消耗问题。
- localStorage 缺点:1.需要手动删除保存的数据;2.只支持字符串类型,JSON 类型需要通过
JSON.stringify()转化。 - localStorage 使用场景:利用 localStorage 可以存放一些稳定的资源和base64的图片等
localStorage 的使用方法
try {
localStorage.setItem(key, value);
} catch(e) {
if (isQuotaExceeded(e)) {
// Storage full, maybe notify user or do some clean-up
}
}
function isQuotaExceeded(e) {
var quotaExceeded = false;
if (e) {
if (e.code) {
switch (e.code) {
case 22:
quotaExceeded = true;
break;
case 1014:
// Firefox
if (e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
quotaExceeded = true;
}
break;
}
} else if (e.number === -2147024882) {
// Internet Explorer 8
quotaExceeded = true;
}
}
return quotaExceeded;
}
sessionStorage
sessionStorage 和 localStorage 一致,唯一大的区别在于 sessionStorage 是会话级别的存储
- 会话级别的
sessionStorage也就是在浏览器页面关闭后,这个存储也就消失了。 - sessionStorage 的场景:sessionStorage 可以用于保存一些临时的数据,防止页面消失后数据就没了,比如表单填写和用户的浏览器记录等。
localStorage 和 sessionStorage 的差别
两者存储时间上的差别,localStorage 是永久的,sessionStorage 是会话型的浏览器关闭后就会消失两者同源下数据共享的差别,localStorage 在同源环境下不同页面之间可以数据的共享,但是 sessionStorage 中同源下数据是不能共享的。
postMessage 可以解决同源环境下页面的通信问题。
indexedDB
浏览器提供的非关系型数据库,indexedDB 提供大量的接口提供查询功能,还能建立查询。
- 以键值对的形式存储值,包括 js 对象
- indexedDB 是异步的,存入数据不会导致页面卡顿。
- indexedDB 支持事务,事务是一系列操作过程中发生了错误,数据库会回退到操作事务之前的状态。
- 同源限制,不同源的数据库不能访问。
- 存储空间没有限制。
webSQL
已废弃,旨在通过 js 语句操控 sql 语句完成对数据的读写。
参考
《图解HTTP》