Stories

Detail Return Return

瀏覽器存儲及JavaScript重寫LocalStorage方法實現瀏覽器本地存儲設置時間問題 - Stories Detail

最近遇到了用户登錄信息本地存儲的問題,所以需要對瀏覽器的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

理解尚淺,望不吝賜教!
user avatar dingtongya Avatar grewer Avatar yinzhixiaxue Avatar front_yue Avatar linx Avatar hyfhao Avatar 54r9rxzy Avatar sy_records Avatar cynthia_59675eba1a2ee Avatar hsr2022 Avatar wubomu Avatar robin_ren Avatar
Favorites 52 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.