2

最近遇到了用户登录信息本地存储的问题,所以需要对浏览器的localStorage的存储时间进行设置,因此重写localStorage方法并在此记录。

浏览器几个存储总结:

  1. localStorage保存的数据(大小5M左右),以“键值对”的形式长期存在。也就是说,每一项数据都有一个键名和对应的值,所有的数据都是以文本格式保存。保存的数据没有过期时间,直到手动去除。
  2. sessionStorage保存的数据(大小5M左右)用于浏览器的一次会话,当会话结束(通常是关闭窗口或标签页),数据被清空。
    sessionStorage与localStrage和Cookie不同的一点在于,即便是相同域名下的两个页面,只要它们不在同一个浏览器窗口中打开,那么它们的sessionStorage内容便无法共享;
  3. cookie以“键值对”的形式存在,是一些数据,存储于你电脑上的文本文件中。

总结cookie、localStorage、sessionStorage异同点对比

相同点:

  • 都是保存在浏览器端,且都是字符串类型的键值对。
  • 都遵循同源策略:当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面
    当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,
    即检查是否同源,只有和百度同源的脚本才会被执行。

不同点:

  • 传递方式不同
  1. cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
  2. sessionStorage和loaclStorage不会自动把数据发给服务器,仅在本地保存。
  • 数据大小不同
  1. cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。存储大小限制也不同,cookie数据不能超过4KB,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
  2. sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或者更大。
  • 数据有效期不同
  1. cookie:只在设置cookie过期时间之前一直有效,即使窗口或浏览器关闭;
    localStorage:始终有效,窗口或浏览器关闭也一直保存,除非手动删除,因此用作持久数据;
    sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持。
  • 作用域不同
  1. cookie:在所有同源窗口中都是共享的;
    localStorage:在所有同源窗口中也都是共享的;
    sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面。

手动封装LocalStorage方法。

  • setItem()实现思路及代码
    首先,changeHourToMs()方法:用于判断调用setItem方法时如果传入了小时,将其转化为毫秒,因为获取当前时间时是毫秒级时间。同时对于为传入expires或传入expires非法情况进行拦截。
    然后,调用Object.assign()方法:将初始化的数据与传入的数组合并,更新传入的数据。
    其次,判断options.expires方法是确定options.expires属性存在时,需要将整个对象的数据进行格式转换存入。
    否则,如果options.expires属性不存在,则意味着没有时间限制,只需存储其name和Value,而不关注存储的时间和时常,存入即可。
  setItem(params) {
    const changeToMs = 60 * 60 * 1000;

    function changeHourToMs(params) {
      if (!Object.prototype.hasOwnProperty.call(params, "expires")) {
        return;
      }
      if (!isNumber(params.expires)) {
        console.log("expires属性输入有误,应输入数字!")
        return;
      }
      params.expires = parseFloat(params.expires) * changeToMs;
    }

    const obj = {
      name: '',
      value: '',
      expires: 24 * 60 * 60 * 1000,
      startTime: new Date().getTime()// 存入缓存的时间
    }
    const options = {};
    changeHourToMs(params);
    // 将obj和传进来的params合并(首先与Obj合并指定必要变量,然后与输入的params合并,如果key存在则添加value,否则添加key和value)
    Object.assign(options, obj, params);
    if (options.expires) {// 如果options.expires设置了的话,以options.name为key,options为值放进去
      localStorage.setItem(options.name, JSON.stringify(options));
    } else {
      // 如果options.expires没有设置,就判断一下value的类型
      const type = Object.prototype.toString.call(options.value);
      // 如果value是对象或者数组对象的类型,就先用JSON.stringify转一下,再存进去
      if (type === '[object Object]') {
        options.value = JSON.stringify(options.value);// 转换为JSON字符串
      }
      if (type === '[object Array]') {
        options.value = JSON.stringify(options.value);
      }
      localStorage.setItem(options.name, options.value);
    }
  }
  • getItem()实现思路及代码
    首先通过name取到数据,并将数据尝试进行Json格式的转换。
    然后确保数据非null,判断是否传入了options.expires属性,如有进行下一步操作,否则将值返回。
    下一步操作:获取当前时间做差,判断若超时直接清空缓存,并采用阻塞提示,用户信息失效,请重新登录,点击确定后跳转到登陆页面。

附:完整代码如下;

import {isNumber} from "lodash";
import router from "umi/router";
import {Modal} from 'antd';

export default class Storage {
  constructor(name) {
    this.name = 'storage';
  }

// 使用说明:该类使用需要先初始化一个对象。
// setItem必须传入的值为:name,vlaue.
// expires为限制时间默认为一天,如有需要可传入存储的时间(以小时为单位)
// startTime默认获取当前时间,无需传入
  setItem(params) {
    const changeToMs = 60 * 60 * 1000;

    function changeHourToMs(params) {
      if (!Object.prototype.hasOwnProperty.call(params, "expires")) {
        return;
      }
      if (!isNumber(params.expires)) {
        console.log("expires属性输入有误,应输入数字!")
        return;
      }
      params.expires = parseFloat(params.expires) * changeToMs;
    }

    const obj = {
      name: '',
      value: '',
      expires: 24 * 60 * 60 * 1000,
      startTime: new Date().getTime()// 存入缓存的时间
    }
    const options = {};
    changeHourToMs(params);
    // 将obj和传进来的params合并(首先与Obj合并指定必要变量,然后与输入的params合并,如果key存在则添加value,否则添加key和value)
    Object.assign(options, obj, params);
    if (options.expires) {// 如果options.expires设置了的话,以options.name为key,options为值放进去
      localStorage.setItem(options.name, JSON.stringify(options));
    } else {
      // 如果options.expires没有设置,就判断一下value的类型
      const type = Object.prototype.toString.call(options.value);
      // 如果value是对象或者数组对象的类型,就先用JSON.stringify转一下,再存进去
      if (type === '[object Object]') {
        options.value = JSON.stringify(options.value);// 转换为JSON字符串
      }
      if (type === '[object Array]') {
        options.value = JSON.stringify(options.value);
      }
      localStorage.setItem(options.name, options.value);
    }
  }

  // 拿到缓存
  getItem(name) {
    let item = localStorage.getItem(name);
    try {    // 先将拿到的试着进行json转为对象的形式,不可以的话直接返回字符串
      item = JSON.parse(item);
    } catch (error) {
      console.log(error);
      item = item;
    }
    if (item !== null) {
      if (item.startTime) {    // 如果有startTime的值,说明设置了失效时间
        const date = new Date().getTime();
        if (date - item.startTime > item.expires) {// 判断是否超时
          localStorage.removeItem(name);// 清除超时缓存
          Modal.warning({
            content: '用户授权已失效,请重新登录!',
            onOk() {
              router.push("/user/login");
            },
          });
          return null;
        }
        return item.value;        // 缓存未过期,返回值

      }
    }
    return item;    // 如果没有设置失效时间,直接返回值

  }

  removeItem(name) {
    localStorage.removeItem(name);
  }

  clear() {
    localStorage.clear();
  }
}

image.png

image.png

理解尚浅,望不吝赐教!

很白的小白
145 声望125 粉丝