切换语言为:繁体

全面深入对比Cookie、LocalStorage、SessionStorage三者差异性

  • 爱糖宝
  • 2024-10-16
  • 2042
  • 0
  • 0

三者基本使用

1. Cookie 的基本使用

设置 Cookie

function setCookie(name, value, days) {
    let expires = "";
    if (days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + (value || "") + expires + "; path=/";
}

// 示例:设置 Cookie 有效期为 7 天
setCookie('username', 'bob', 7);

获取 Cookie

function getCookie(name) {
    const nameStr = name + "=";
    const ca = document.cookie.split(';');
    for (let i = 0; i < ca.length; i++) {
        let c = ca[i];
        while (c.charAt(0) === ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameStr) === 0) return c.substring(nameStr.length, c.length);
    }
    return null;
}

// 示例:获取 Cookie
const username = getCookie('username');
console.log(username); // 输出:bob

删除 Cookie

function delCookie(name) {
    document.cookie = name + '=; Max-Age=-99999999;'; // 立即过期
}

// 示例:删除 Cookie
delCookie('username');

设置安全标志

为了提高安全性,可以设置 Secure 和 HttpOnly 标志。

  • Secure:表示 Cookie 只能通过 HTTPS 协议传输。

  • HttpOnly:表示 Cookie 不能通过 JavaScript 访问,只能通过 HTTP 请求访问。

// 设置带有 Secure 和 HttpOnly 标志的 Cookie
document.cookie = "username=张三; Secure; HttpOnly; path=/";

5. 完整示例

2. localStorage 的基本使用

localStorage 是浏览器提供的一种存储机制,允许网页在用户的本地计算机上保存数据。这些数据即使在浏览器关闭后仍然存在,直到被用户或网站主动清除。以下是 localStorage 的基本使用方法:

设置 localStorage

使用 setItem 方法将数据存储到 localStorage 中。

// 存储字符串
localStorage.setItem('username', '张三');

// 存储数字
localStorage.setItem('age', '25');

// 存储对象(需要先转换为 JSON 字符串)
const user = { name: '李四', age: 30 };
localStorage.setItem('user', JSON.stringify(user));

// `localStorage` 存储布尔值时,需要注意布尔值需要转换成字符串形式才能存储,并且在读取时需要将其还原成布尔值
localStorage.setItem('isLoggedIn', 'true'); // 存储 true 
localStorage.setItem('isFirstVisit', 'false'); // 存储 false

获取 localStorage

使用 getItem 方法从 localStorage 中获取数据。

// 获取字符串
const username = localStorage.getItem('username');
console.log(username); // 输出: 张三

// 获取数字
const age = localStorage.getItem('age');
console.log(Number(age)); // 输出: 25

// 获取对象(需要先解析 JSON 字符串)
const userString = localStorage.getItem('user');
const user = JSON.parse(userString || '{}');
console.log(user); // 输出: { name: '李四', age: 30 }

// 获取布尔值 
const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true'; // 转换为布尔值
console.log(isLoggedIn); // 输出: true 
const isFirstVisit = localStorage.getItem('isFirstVisit') === 'false'; // 转换为布尔值 
console.log(isFirstVisit); // 输出: false

删除 localStorage

使用 removeItem 方法从 localStorage 中删除特定的数据。

// 删除单个数据
localStorage.removeItem('username');

// 删除所有数据
localStorage.clear();

4. 检查 localStorage 是否可用

在某些情况下,localStorage 可能不可用(例如,用户禁用了本地存储)。可以通过以下方式检查 localStorage 是否可用:

function isLocalStorageAvailable() {
  try {
    const key = 'test';
    localStorage.setItem(key, key);
    localStorage.removeItem(key);
    return true;
  } catch (e) {
    return false;
  }
}

if (isLocalStorageAvailable()) {
  console.log('localStorage 可用');
} else {
  console.log('localStorage 不可用');
}

5. 监听 storage 事件

当 localStorage 发生变化时,会触发 storage 事件。可以在页面中监听这个事件来响应存储的变化。

window.addEventListener('storage', (event) => {
  console.log('存储发生变化:', event.key, event.newValue);
});

结论

  • setItem(key, value):存储数据。

  • getItem(key):获取数据。

  • removeItem(key):删除特定数据。

  • clear():删除所有数据。

  • storage 事件:监听存储变化。


3. sessionStorage 的基本使用

SessionStorage 是 Web Storage API 的一部分,用于在浏览器会话期间存储数据。数据存储在同一窗口或标签页内,关闭窗口或标签页后数据会被清除。

设置 sessionStorage

使用 setItem 方法将数据存储到 sessionStorage 中。

// 存储字符串
sessionStorage.setItem('username', '张三');

// 存储数字
sessionStorage.setItem('age', '25');

// 存储对象(需要先转换为 JSON 字符串)
const user = { name: '李四', age: 30 };
sessionStorage.setItem('user', JSON.stringify(user));

// `sessionStorage` 存储布尔值时,同样需要注意将布尔值转换为字符串形式进行存储,并在读取时将其还原为布尔值。
sessionStorage.setItem('isLoggedIn', 'true'); // 存储 true 
sessionStorage.setItem('isFirstVisit', 'false'); // 存储 false

获取 sessionStorage

使用 getItem 方法从 sessionStorage 中获取数据。

// 获取字符串
const username = sessionStorage.getItem('username');
console.log(username); // 输出: 张三

// 获取数字
const age = sessionStorage.getItem('age');
console.log(Number(age)); // 输出: 25

// 获取对象(需要先解析 JSON 字符串)
const userString = sessionStorage.getItem('user');
const user = JSON.parse(userString || '{}');
console.log(user); // 输出: { name: '李四', age: 30 }

// 获取布尔值 
const isLoggedIn = sessionStorage.getItem('isLoggedIn') === 'true'; // 转换为布尔值 
console.log(isLoggedIn); // 输出: true 
const isFirstVisit = sessionStorage.getItem('isFirstVisit') === 'false'; // 转换为布尔值 
console.log(isFirstVisit); // 输出: false

删除 sessionStorage

使用 removeItem 方法从 sessionStorage 中删除特定的数据。

// 删除单个数据
sessionStorage.removeItem('username');

// 删除所有数据
sessionStorage.clear();

4. 检查 sessionStorage 是否可用

在某些情况下,sessionStorage 可能不可用(例如,用户禁用了本地存储)。可以通过以下方式检查 sessionStorage 是否可用:

function isSessionStorageAvailable() {
  try {
    const key = 'test';
    sessionStorage.setItem(key, key);
    sessionStorage.removeItem(key);
    return true;
  } catch (e) {
    return false;
  }
}

if (isSessionStorageAvailable()) {
  console.log('sessionStorage 可用');
} else {
  console.log('sessionStorage 不可用');
}

5. 监听 storage 事件

当 sessionStorage 发生变化时,会触发 storage 事件。可以在页面中监听这个事件来响应存储的变化。

window.addEventListener('storage', (event) => {
  console.log('存储发生变化:', event.key, event.newValue);
});

结论

  • setItem(key, value):存储数据。

  • getItem(key):获取数据。

  • removeItem(key):删除特定数据。

  • clear():删除所有数据。

  • storage 事件:监听存储变化。

基础封装

Cookie 工具类 CookieUtils  是ts版本的 js把类型去除即可

export class CookieUtils {
  static setCookie(name: string, value: string, options?: {
    expires?: number | Date;
    path?: string;
    domain?: string;
    secure?: boolean;
    httpOnly?: boolean;
  }): void {
    let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;

    if (options?.expires) {
      const expires = typeof options.expires === 'number'
        ? new Date(Date.now() + options.expires * 24 * 60 * 60 * 1000)
        : options.expires;
      cookieString += `; expires=${expires.toUTCString()}`;
    }

    if (options?.path) {
      cookieString += `; path=${options.path}`;
    }

    if (options?.domain) {
      cookieString += `; domain=${options.domain}`;
    }

    if (options?.secure) {
      cookieString += '; Secure';
    }

    if (options?.httpOnly) {
      cookieString += '; HttpOnly';
    }

    document.cookie = cookieString;
  }

  static getCookie(name: string): string | null {
    const cookieArray = document.cookie.split('; ');
    for (let i = 0; i < cookieArray.length; i++) {
      const cookie = cookieArray[i].split('=');
      if (cookie[0].trim() === encodeURIComponent(name)) {
        return decodeURIComponent(cookie[1]);
      }
    }
    return null;
  }

  static deleteCookie(name: string): void {
    document.cookie = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
  }
}

// 使用示例

// 设置一个简单的 Cookie
CookieUtils.setCookie('username', '张三');

// 设置带有过期时间的 Cookie
CookieUtils.setCookie('username', '张三', { expires: 7, path: '/', domain: '.example.com', secure: true, httpOnly: true });

// 获取 Cookie
const username = CookieUtils.getCookie('username');
console.log(username); // 输出: 张三

// 删除 Cookie
CookieUtils.deleteCookie('username');

'localStorage' | 'sessionStorage' 合并封装 默认 localStorage

export class StorageUtils {
  private storageType: 'localStorage' | 'sessionStorage'

  constructor(storageType: 'localStorage' | 'sessionStorage' = 'localStorage') {
    this.storageType = storageType
  }

  private getStorage(): Storage {
    return this.storageType === 'localStorage' ? localStorage : sessionStorage
  }

  setItem(key: string, value: any): void {
    this.getStorage().setItem(key, JSON.stringify(value))
  }

  getItem(key: string): any {
    const value = this.getStorage().getItem(key)
    return value ? JSON.parse(value) : null
  }

  removeItem(key: string): void {
    this.getStorage().removeItem(key)
  }

  clear(): void {
    this.getStorage().clear()
  }
}

// 使用示例

// 使用默认的 LocalStorage
const localStorageUtils = new StorageUtils()

// 设置数据
localStorageUtils.setItem('user', { name: '张三', age: 30 })

// 获取数据
const user = localStorageUtils.getItem('user')
console.log(user) // 输出: { name: '张三', age: 30 }

// 删除数据
localStorageUtils.removeItem('user')

// 清空所有数据
localStorageUtils.clear()

// 使用 SessionStorage
const sessionStorageUtils = new StorageUtils('sessionStorage')

// 设置数据
sessionStorageUtils.setItem('user', { name: '李四', age: 25 })

// 获取数据
const sessionUser = sessionStorageUtils.getItem('user')
console.log(sessionUser) // 输出: { name: '李四', age: 25 }

// 删除数据
sessionStorageUtils.removeItem('user')

// 清空所有数据
sessionStorageUtils.clear()

注意:localStorage' | 'sessionStorage 一样也可以过期时间封装(但是好像一般不需要)还是给个参考吧

export class StorageExpiringUtils {
  private storage: Storage

  constructor(storageType: 'localStorage' | 'sessionStorage' = 'localStorage') {
    this.storage =
      storageType === 'localStorage' ? localStorage : sessionStorage
  }

  setExpiration(key: string, value: any, ttlInSeconds: number): void {
    const now = new Date().getTime()
    const item = {
      value,
      expiration: now + ttlInSeconds * 1000,
    }
    this.storage.setItem(key, JSON.stringify(item))
  }

  getExpiration(key: string): any {
    const itemStr = this.storage.getItem(key)
    if (!itemStr) {
      return null
    }

    const item = JSON.parse(itemStr)
    const now = new Date().getTime()

    if (item.expiration < now) {
      this.removeItem(key)
      return null
    }

    return item.value
  }

  removeItem(key: string): void {
    this.storage.removeItem(key)
  }

  clear(): void {
    this.storage.clear()
  }
}

// 使用示例

// 创建 StorageExpiringUtils 实例,默认使用 LocalStorage
const localStorageExpiringUtils = new StorageExpiringUtils()

// 设置带过期时间的数据
localStorageExpiringUtils.setExpiration('token', 'abc123', 60 * 60) // 1小时后过期

// 获取带过期时间的数据
const token = localStorageExpiringUtils.getExpiration('token')
console.log(token) // 输出: abc123

// 等待一段时间后再次获取(假设已经过期)
setTimeout(() => {
  const expiredToken = localStorageExpiringUtils.getExpiration('token')
  console.log(expiredToken) // 输出: null
}, 60 * 60 * 1000)

// 创建 StorageExpiringUtils 实例,使用 SessionStorage
const sessionStorageExpiringUtils = new StorageExpiringUtils('sessionStorage')

// 设置带过期时间的数据
sessionStorageExpiringUtils.setExpiration('token', 'abc', 60 * 60) // 1小时后过期

// 获取带过期时间的数据
const sessionToken = sessionStorageExpiringUtils.getExpiration('token')
console.log(sessionToken) // 输出: abc

// 等待一段时间后再次获取(假设已经过期)
setTimeout(() => {
  const expiredSessionToken = sessionStorageExpiringUtils.getExpiration('token')
  console.log(expiredSessionToken) // 输出: null
}, 60 * 60 * 1000)

三者对比

1. 存储容量

  • Cookie:通常每个 Cookie 的大小限制在 4KB 左右,整个域名下的 Cookie 数量也有一些限制(通常最多 20 个)。

  • LocalStorage:存储容量较大,通常限制在 5MB 到 10MB 不等,取决于浏览器。

  • SessionStorage:和 LocalStorage 类似,通常限制在 5MB 到 10MB,不同的是 SessionStorage 的数据会在会话结束后清除。

2. 数据持久性

  • Cookie:可以设置过期时间,默认情况下,浏览器关闭后,未设置过期时间的 Cookie 会被删除。可以长期保存数据。

  • LocalStorage:数据没有过期时间,即使浏览器关闭,数据也会保留,直到显式地删除或清除。

  • SessionStorage:数据只在浏览器窗口或标签页开启期间有效,关闭窗口或标签页后,数据会被清除。

3. 存储方式

  • Cookie:每次请求都会被发送到服务器,支持跨域,但因为每次请求都携带,会增加带宽开销。

  • LocalStorage 和 SessionStorage:数据存储在客户端,不会随每个请求传输,因此不会增加网络负担。

4. 访问方式

  • Cookie:可以通过 document.cookie 访问,格式较为复杂,例如需要手动解析字符串。

  • LocalStorage 和 SessionStorage:通过 localStorage 和 sessionStorage 对象进行访问,简单易用,支持 setItemgetItemremoveItem 和 clear 等方法。

5. 安全性

  • Cookie:可以设置 HttpOnly(防止 JavaScript 访问)和 Secure(只在 HTTPS 环境下传输)标志,增强安全性。

  • LocalStorage 和 SessionStorage:不支持这些安全标志,数据更容易受到客户端脚本攻击(如 XSS)。

6. 适用场景

  • Cookie:适合需要在服务器与客户端之间共享状态的应用,例如用户认证信息、分布式追踪等。

  • LocalStorage:适合存储不需要频繁交换的数据,例如用户的偏好设置、缓存数据等。

  • SessionStorage:适合一次性会话的数据存储,例如表单填写过程中的临时数据。

小结

  • Cookie:适合持久且需要与服务器通信的数据,有严格的大小限制。

  • LocalStorage:适合长期存储数据,大小限制较大,数据不会随会话结束而消失。

  • SessionStorage:适合存储会话相关的数据,数据在浏览器窗口关闭后被清除。

Cookie、LocalStorage 和 SessionStorage 的共享特性

1. 同域名下的共享

  • Cookie

    • 同域名下:Cookie 在同一域名下的所有页面之间是可以共享的。只要设置了相同的 path 属性,不同页面都可以访问同一个 Cookie。

    • 不同子域名:可以通过设置 domain 属性来实现跨子域名的共享。例如,设置 domain=.example.com 可以使 a.example.com 和 b.example.com 共享同一个 Cookie。

  • LocalStorage

    • 同域名下:LocalStorage 在同一域名下的所有页面之间是可以共享的。不同页面可以访问同一个 LocalStorage。

    • 不同子域名:LocalStorage 不能跨子域名共享。a.example.com 和 b.example.com 会有各自的 LocalStorage。

  • SessionStorage

    • 同域名下:SessionStorage 在同一域名下的所有页面之间是不共享的。每个页面打开的新标签页或新窗口都会有独立的 SessionStorage。

    • 不同子域名:SessionStorage 也不能跨子域名共享。a.example.com 和 b.example.com 会有各自的 SessionStorage。

2. 不同域名下的共享

  • Cookie

    • 不同域名下:默认情况下,Cookie 不能跨域名共享。但是,可以通过设置 domain 属性来实现一定程度的跨子域名共享。

    • 完全不同的顶级域名:完全不同的顶级域名(如 example.com 和 example.org)之间无法直接共享 Cookie。

  • LocalStorage

    • 不同域名下:LocalStorage 不能跨域名共享。example.com 和 example.org 会有各自的 LocalStorage。

  • SessionStorage

    • 不同域名下:SessionStorage 不能跨域名共享。example.com 和 example.org 会有各自的 SessionStorage。

3. 不同页面标签之间的共享

  • Cookie

    • 不同页面标签:在同一域名下的不同页面标签之间,Cookie 是共享的。只要设置了相同的 path 属性,不同页面标签可以访问同一个 Cookie。

  • LocalStorage

    • 不同页面标签:在同一域名下的不同页面标签之间,LocalStorage 是共享的。不同页面标签可以访问同一个 LocalStorage。

  • SessionStorage

    • 不同页面标签:在同一域名下的不同页面标签之间,SessionStorage 是不共享的。每个页面标签打开的新窗口或新标签页都会有独立的 SessionStorage。

总结

  • Cookie

    • 同域名下:共享

    • 不同子域名:通过设置 domain 属性可以共享

    • 不同顶级域名:不共享

    • 不同页面标签:共享

  • LocalStorage

    • 同域名下:共享

    • 不同子域名:不共享

    • 不同顶级域名:不共享

    • 不同页面标签:共享

  • SessionStorage

    • 同域名下:不共享

    • 不同子域名:不共享

    • 不同顶级域名:不共享

    • 不同页面标签:不共享

0条评论

您的电子邮件等信息不会被公开,以下所有项均必填

OK! You can skip this field.