前端存储那些事二

一、两种storage 如何监听他们的变化?

    localStorage 和 sessionStorage 并没有内置的事件监听机制,因此无法直接监听它们的变化。但是可以使用以下方法实现监听:

(1)使用 storage 事件:localStoragesessionStorage 对象都会触发 storage 事件,当其他窗口或标签页对存储进行更改时会触发该事件。您可以通过添加 storage 事件监听器来捕获变化,并在回调函数中执行相应的操作。

// 方法一:监听 storage 事件
window.addEventListener('storage', function(event) {
   if (event.storageArea === localStorage) {
        // localStorage 发生变化
        console.log('localStorage 发生变化');
        console.log('Key发生变化的值是: ' + event.key);
        console.log('New Value发生变化的值是: ' + event.newValue);
    } else if (event.storageArea === sessionStorage) {
         // sessionStorage 发生变化
         console.log('sessionStorage 发生变化');
         console.log('Key发生变化的值是: ' + event.key);
         console.log('New Value发生变化的值是:' + event.newValue);
    }
});

(2)使用定时器:通过使用定时器,在一定的时间间隔内轮询检查存储的值是否发生变化,并在变化时执行相应的操作。

 // 监听 localStorage 变化
 function startLocalStorageListener() {
    // 获取初始的 localStorage 值
    var initialValue = JSON.stringify(localStorage);

    // 每隔一段时间检测 localStorage 是否变化
    setInterval(function() {
        var updatedValue = JSON.stringify(localStorage);
        if (updatedValue !== initialValue) {
          // localStorage 发生变化,执行相应的操作
          console.log("localStorage 发生变化");
          // 更新初始的 localStorage 值
          initialValue = updatedValue;
         }
     }, 1000);
  }

 // 监听 sessionStorage 变化
 function startSessionStorageListener() {
    // 获取初始的 sessionStorage 值
    var initialValue = JSON.stringify(sessionStorage);

    // 每隔一段时间检测 sessionStorage 是否变化
    setInterval(function() {
        var updatedValue = JSON.stringify(sessionStorage);
        if (updatedValue !== initialValue) {
        // sessionStorage 发生变化,执行相应的操作
            console.log("sessionStorage 发生变化");
            // 更新初始的 sessionStorage 值
            initialValue = updatedValue;
            }
     }, 1000); // 检测间隔为1秒
}

// 启动监听
startLocalStorageListener();
startSessionStorageListener();

(3)使用 Proxy 对象:通过创建一个 Proxy 对象来代理localStoragesessionStorage,可以拦截对存储的读写操作,并在变化时执行自定义的操作。

// 监听存储变化的封装函数
function addStorageListener(storageType, callback) {
  // 根据存储类型选择 localStorage 或 sessionStorage
  var storage = (storageType === 'localStorage') ? localStorage : sessionStorage;

  // 创建 Proxy 对象
  var proxy = new Proxy(storage, {
    set: function(target, key, value) {
      // 存储值发生变化,执行回调函数
      callback(key, value);

      // 在实际存储前设置新的值
      target[key] = value;

      return true;
    }
  });
}

// 使用示例
addStorageListener('localStorage', function(key, value) {
  console.log('localStorage 发生改变');
  console.log('Key发生变化的值是: ' + key);
  console.log('Value发生变化的值是: ' + value);
});

addStorageListener('sessionStorage', function(key, value) {
  console.log('sessionStorage 发生改变');
  console.log('Key发生变化的值是: ' + key);
  console.log('Value发生变化的值是: ' + value);
});

(4)封装自定义函数:使用自定义的封装函数来检测 localStoragesessionStorage 的变化,您可以创建一个函数,该函数在存储值发生变化时被调用,并通过监听 storage 事件来触发回调函数。

// 监听存储变化的封装函数
function addStorageListener(storageType, callback) {
  // 根据存储类型选择 localStorage 或 sessionStorage
  var storage = (storageType === 'localStorage') ? localStorage : sessionStorage;

  // 事件监听器回调函数
  function storageEventListener(event) {
    if (event.storageArea === storage) {
      // 存储值发生变化,执行回调函数
      callback(event.key, event.newValue);
    }
  }

  // 添加事件监听器
  window.addEventListener('storage', storageEventListener);
}

// 使用示例
addStorageListener('localStorage', function(key, value) {
  console.log('localStorage 发生改变');
  console.log('Key发生变化的值是: ' + key);
  console.log('Value发生变化的值是: ' + value);
});

addStorageListener('sessionStorage', function(key, value) {
  console.log('sessionStorage 发生改变');
  console.log('Key发生变化的值是: ' + key);
  console.log('Value发生变化的值是: ' + value);
});

二、如果要给localstorage存储的数据设置过期时间,你会怎么设计技术方案?

(1)手动添加时间戳:在存储数据时,同时将数据和过期时间(时间戳)一起存储。在读取数据时,先检查当前时间是否超过了过期时间,如果是则认为数据已过期,可以进行相应的处理。

// 存储数据到 localStorage,并设置过期时间
function setStorageTime(key, value, time) {
  var dataTime = time * 60 * 1000; // 转换为毫秒
  var item = {
    value: value,
    expiration: Date.now() + dataTime // 当前时间加上过期时间
  };
  localStorage.setItem(key, JSON.stringify(item));
}

// 从 localStorage 读取数据,并检查过期时间
function getStorageTime(key) {
  var item = localStorage.getItem(key);
  if (item) {
    item = JSON.parse(item);
    if (item.expiration && Date.now() > item.expiration) {
      // 数据已过期
      localStorage.removeItem(key);
      return null;
    }
    return item.value;
  }
  return null;
}

// 使用示例
setStorageTime('username', 'Cheng Dong', 10); // 存储数据并设置过期时间为 10 分钟
var username = getStorageTime('username'); // 读取数据
console.log(username); // 输出 'Cheng Dong',如果在 10 分钟内执行,否则输出 null

(2)结合定时器清理过期数据:使用定时器定期检查存储的数据的过期时间,并清理已过期的数据。您可以使用 setInterval 函数设置一个定时器,在固定的时间间隔内检查存储的数据的过期时间,并删除已过期的数据。这样可以保持存储空间的有效利用,同时确保过期数据不会被使用。

// 存储数据到 localStorage,并设置过期时间
function setStorageTime(key, value, time) {
  var dataTime = time * 60 * 1000; // 转换为毫秒
  var item = {
    value: value,
    expiration: Date.now() + dataTime // 当前时间加上过期时间
  };
  localStorage.setItem(key, JSON.stringify(item));
}

// 从 localStorage 读取数据,并检查过期时间
function getStorageTime(key) {
  var item = localStorage.getItem(key);
  if (item) {
    item = JSON.parse(item);
    if (item.expiration && Date.now() > item.expiration) {
      // 数据已过期
      localStorage.removeItem(key);
      return null;
    }
    return item.value;
  }
  return null;
}

// 清理过期数据
function clearDataTime() {
  for (var i = 0; i < localStorage.length; i++) {
    var key = localStorage.key(i);
    var item = localStorage.getItem(key);
    if (item) {
      item = JSON.parse(item);
      if (item.expiration && Date.now() > item.expiration) {
        // 数据已过期,从 localStorage 中移除
        localStorage.removeItem(key);
      }
    }
  }
}

// 设置定时器定期清理过期数据
setInterval(function() {
  clearDataTime();
}, 60 * 1000); // 每分钟清理一次

// 使用示例
setStorageTime('username', 'Cheng Dong', 10); // 存储数据并设置过期时间为 10 分钟
var username = getStorageTime('username'); // 读取数据
console.log(username); // 输出 'Cheng Dong',如果在 10 分钟内执行,否则输出 null

(3)使用自定义封装函数:创建一个封装函数来包装 localStorage 的存储和读取操作,并在其中实现过期时间的逻辑。该函数可以接收一个过期时间参数,并在存储数据时同时存储过期时间。在读取数据时,检查当前时间是否超过了过期时间,如果是则返回空值或默认值。

// 存储数据到 localStorage,并设置过期时间
function setStorageTime(key, value, time) {
  var dataTime = time * 60 * 1000; // 转换为毫秒
  var item = {
    value: value,
    expiration: Date.now() + dataTime // 当前时间加上过期时间
  };
  localStorage.setItem(key, JSON.stringify(item));
}

// 从 localStorage 读取数据,并检查过期时间
function getStorageTime(key) {
  var item = localStorage.getItem(key);
  if (item) {
    item = JSON.parse(item);
    if (item.expiration && Date.now() > item.expiration) {
      // 数据已过期
      localStorage.removeItem(key);
      return null;
    }
    return item.value;
  }
  return null;
}

// 使用示例
setStorageTime('username', 'Cheng Dong', 10); // 存储数据并设置过期时间为 10 分钟
var username = getStorageTime('username'); // 读取数据
console.log(username); // 输出 'Cheng Dong',如果在 10 分钟内执行,否则输出 null

三、用以上提到的api中的一种或几种来实现跨Tab页通信,你会怎么来做?

(1)localStorage实现跨Tab页通信

// 设置
localStorage.setItem('message', '我是localStorage的值');
// 监听使用
window.addEventListener('storage', function(event) {
  if (event.key === 'message') {
    var message = event.newValue;
    console.log('message:', message);
  }
});

(2)sessionStorage实现跨Tab页通信

sessionStorage.setItem('message', '我是sessionStorage的值');
// 触发自定义事件来通知其他标签页
var event = new Event('sessionStorageUpdated');
window.dispatchEvent(event);

window.addEventListener('storage', function(event) {
  if (event.key === 'message') {
    var message = sessionStorage.getItem('message');
    console.log('message:', message);
  }
});

// 监听自定义事件来检测 `sessionStorage` 的更新
window.addEventListener('sessionStorageUpdated', function() {
  var message = sessionStorage.getItem('message');
  console.log('message:', message);
});

(3)cookie实现跨Tab页通信

// 设置cookie
document.cookie = "message = 我是设置的Cookie值";
// 自定义函数
function getCookie(name) {
  var cookies = document.cookie.split(';');
  for (var i = 0; i < cookies.length; i++) {
    var cookie = cookies[i].trim();
    if (cookie.startsWith(name + "=")) {
      return cookie.substring(name.length + 1);
    }
  }
  return "";
}
// 使用
var message = getCookie("message");
console.log("message:", message);

注:

1、Cookies 在每个 HTTP 请求中都会被发送到服务器,而不仅仅限于同一浏览器标签页之间,而且会增加网络传输的负担。

2、Cookies 的大小有限制,一般为几 KB。因此,适用于较小量的数据通信。

3、Cookies 受浏览器安全问题。

4、storage 事件只在其他标签页中触发,而在进行写入操作的标签页上不会触发该事件。

5、localStorage 存储的数据是共享的,因此需要小心处理数据的同步和更新,以避免冲突和数据不一致的问题。

6、storage 事件在更新同一 sessionStorage 的标签页之间不会触发。

7、storage 事件无法提供更改的具体值,因此我们需要手动读取 sessionStorage 的值来获取更新的数据。

8、sessionStorage 实现跨Tab页面的通信没有localStorage 那样直接和简单。

四、cookie是否会导致安全性问题?

cookie会导致安全性问题:

例如:

  1、信息泄露:不适当地处理和存储 Cookie 可能导致敏感信息泄露

  解决办法:

  • 仅在必要的情况下存储敏感信息,并在不再需要时立即删除。

  • 使用加密技术来保护敏感信息的存储和传输。

    2、会话劫持:攻击者通过获取合法用户的会话信息,冒充该用户与系统进行交互,从而获取未经授权

    的访问权限或执行恶意操作。

    解决办法:

  • 使用安全的传输层协议(如 HTTPS)来加密会话数据,防止被窃听和篡改。

  • 定期更新会话 Cookie 的值,使攻击者更难截获有效的会话。

    3、跨站点脚本攻击(XSS):攻击者利用该漏洞向目标网站注入恶意脚本代码,从而在用户的浏览器

    中执行恶意代码。

    解决办法:

  • 对用户输入进行验证和过滤,确保不允许注入恶意脚本。

  • 对敏感的 Cookie 设置 Secure 标记,仅在通过 HTTPS 连接时传输。

    4、跨站点请求伪造(CSRF):攻击者通过诱使用户点击恶意链接或访问包含恶意代码的页面,以利用

    用户在目标网站上的已认证会话

    解决办法:

  • 使用 CSRF 令牌(也称为防护令牌)来验证请求的来源和合法性。

  • 在关键操作(如修改或删除数据)上使用 POST 请求而不是 GET 请求。

  • 验证请求的来源,例如检查 Referer 头部。

五、同域名下的 sessionStorage 数据会不会共享

   sessionStorage 的作用域限定在当前会话中,关闭窗口或标签页后数据将被清除。即使是同一域名的不同窗口或者标签,他们之间的sessionStorage 数据也是相互隔离的,无法直接共享。每个窗口或者标签都有自己独立的sessionStorage 对象,他们之间的数据互不干扰。

六、不同的子域名之间cookie互通吗

        不同的子域名之间cookie是不互通的,每个子域名都会被视为不同的域,浏览器会将其视为独立的上下文,各自维护自己的cookie