Skip to main content

本地存储

分类:

  • localStorage
  • sessionStorage
  • cookie/Token
  • indexDB
  • ......

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 StoragelocalStoragesessionStorage) 它的存储空间更大,存储空间有 2 个限制:全局限制即为浏览器的最大存储空间一般是可用磁盘空间的 50%;组限制为全局限制的 20%,且它至少有 10MB,最大为 2GB 存储空间;IndexedDB 也受到源的限制;Web Storage 只能存储字符串,IndexedDB 可以存储字符串、BlobArrayBuffer;多数操作都是异步执行的

Token

token 是服务端生成的一串字符串,比如基于 jwt 创建,原理参考 https://cloud.tencent.com/developer/article/1784276

  • 用户登录后,服务端返回 token
  • 存放在 localStorage
  • 请求时带上,可放在请求头或 body 里
  • axios 响应拦截,统一处理 token 过期,可以重定向登录界面或者无感刷新 token

无感刷新

参考

实现步骤

  1. 判断请求的 token 过期,指定一个状态码作为过期标识并响应;客户端暂存请求队列
  2. 客户端收到对应状态码后更新本地 token,发起刷新 token 的请求
  3. 更新本地 token
  4. 重发请求,清空队列

并发请求如何防止多次刷新 token?

  • isRefreshing 锁,不重复发送刷新 token 的请求
  • 刷新 token 期间要阻塞其他请求

token 放在请求头还是 body 有什么区别?【WIP】

  • 方便,和数据解耦
  • 安全性问题?