本地存储
分类:
- localStorage
- sessionStorage
- cookie/Token
- indexDB
- ......
Cookie
Cookie 的作用是维护服务端和客户端的会话状态,简而言之就是告诉服务器当前客户端用户的一些信息;每个 Cookie 大小不超过 4kb。Cookie 的作用域是和 domain(域名或 ip)绑定的,端口无关
分类
- 会话 cookie
- 持久 cookie
Cookie 通常是由服务端生成,然后通过响应头的 Set-Cookie
发送给客户端浏览器:
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: my_cookie=bulandent
浏览器会将 Cookie 保存在本地,并且会在下次请求头部的 Cookie 中附上这个值:
GET /home.html HTTP/1.1
Host: www.example.org
Cookie: my_cookie=bulandent
属性值
- Expires GMT 时间格式
Expires=Fri, 29 Apr 2022 05:29:01 GMT
- Max-Age 单位为秒。通过设置小于等于 0 的数字,可以让一个 cookie 失效。优先级比 expires 高
- Path
- Domain 在希望多个子域名共享 cookie 的场景下,比如 sub1.a.com 和 sub2.a.com(或者再加上父域名 a.com),就需要显式将其设置为 .a.com
- Secure 请求协议必须为 https
- httpOnly 不允许 js 读取,防止 xss 攻击
- samesite 跨站(非跨域)控制
- Strict:跨域请求严禁携带本站 cookie。
- Lax:默认值。可通过顶级导航的方式并使用 GET 请求发时可以携带(目前我没有通过 demo 实现该效果,或者我们可以将其无限接近于 Strict)。在 Chrome 80 版本之后,Cookie 的 SameSite 由原来的 None 改为了 Lax。
- None:会携带 cookie。但前提是 Secure 设置为 true,即只能在 HTTPS 协议下使用(之前的标准没有这个要求)
跨域时如何处理 cookie?
- 解决跨域,开启 CORS
- 默认不会携带 cookie,需要在 open XMLHttpRequest 后,设置 withCredentials 为 true 即可让该跨域请求携带 Cookie。注意此时 access-control-allow-origin 不能为 *,需要指定域名
- 修改 cookie samesite 值,设置为 none,并且 cookie 要带上 secure 值(默认的 lax 值有限制,参考 https://www.zhihu.com/question/373011996)
localStorage
localStorage
的存储不受会话限制而且能够长期存储于客户端浏览器中,直到手动删除或者清除浏览器缓存。它的大小被限制为每个源 5MB 左右
sessionStorage
sessionStorage
对象只会存储会话数据,这意味着当浏览器 tab 页被关闭的时候,对应的数据将被清除。它的大小也被限制为每个源 5MB 左右。除此之外,它还有如下表现:
- 不受页面刷新(包括强制刷新)影响,并且可以在浏览器崩溃并重启后恢复
- 在当前页面通过新标签页或窗口打开一个新页面的时候,新页面会复制父级页面的
sessionStorage
数据 - 使用同一个 URL 打开多个标签页,它们各自的
sessionStorage
数据不同
IndexDB
IndexedDB
相比 Web Storage
(localStorage
和 sessionStorage
) 它的存储空间更大,存储空间有 2 个限制:全局限制即为浏览器的最大存储空间一般是可用磁盘空间的 50%;组限制为全局限制的 20%,且它至少有 10MB,最大为 2GB 存储空间;IndexedDB 也受到源的限制;Web Storage
只能存储字符串,IndexedDB
可以存储字符串、Blob
和 ArrayBuffer
;多数操作都是异步执行的
Token
token 是服务端生成的一串字符串,比如基于 jwt 创建,原理参考 https://cloud.tencent.com/developer/article/1784276
- 用户登录后,服务端返回 token
- 存放在 localStorage
- 请求时带上,可放在请求头或 body 里
- axios 响应拦截,统一处理 token 过期,可以重定向登录界面或者无感刷新 token
无感刷新
参考
实现步骤
- 判断请求的 token 过期,指定一个状态码作为过期标识并响应;客户端暂存请求队列
- 客户端收到对应状态码后更新本地 token,发起刷新 token 的请求
- 更新本地 token
- 重发请求,清空队列
并发请求如何防止多次刷新 token?
- isRefreshing 锁,不重复发送刷新 token 的请求
- 刷新 token 期间要阻塞其他请求
token 放在请求头还是 body 有什么区别?【WIP】
- 方便,和数据解耦
- 安全性问题?