跳至主要內容

数据存储

Yang大约 6 分钟

是直接存储在浏览器中的一小串数据

通常由 Web 服务器使用响应 Set-Cookie HTTP-header 设置的,然后浏览器使用 Cookie HTTP-header 将它们自动添加到(几乎)每个对相同域的请求中

获取

  • 值由 name=value 对组成,以 ; 分隔。每一个都是独立的 cookie
var cookie = document.cookie;
console.log(cookie)

写入

  • 只会更新其中对应 name 的 cookie,而不会涉及其他 cookie
  • cookie 的名称和值可以是任何字符。为了保持有效的格式,它们应该使用内建的 encodeURIComponent 函数对其进行转义
    • encodeURIComponent 编码后的 name=value 对,大小不能超过 4KB
    • 每个域的 cookie 总数不得超过 20+ 左右,具体限制取决于浏览器
document.cookie = 'user=yang' // 只会更新名称为 user 的 cookie
document.cookie = "user=yangwd; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"
console.log(document.cookie)   // // 展示所有 cookie
// 特殊字符(空格),需要编码
let name = "my name";
let value = "name value"

// 将 cookie 编码为 my%20name=name%20value
document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
console.log(document.cookie); // ...; my%20name=name%20value

选项

path

path=/mypath,设置可访问该 cookie 的页面路径

  • url 路径前缀必须是绝对路径,它使得该路径下的页面可以访问该 cookie,默认为当前路径
  • 如果一个 cookie 带有 path=/admin 设置,那么该 cookie 在 /admin/admin/something 下都是可见的,但是在 /home/adminpage 下不可见
  • 通常将 path 设置为根目录:path=/,以使 cookie 对此网站的所有页面可见

domain

domain=site.com,设置可访问 cookie 的域,但是在实际中,有一些限制。无法设置任何域

// 在 site.com
// 使 cookie 可以被在任何子域 *.site.com 访问:
document.cookie = "user=John; domain=site.com"

expires | max-age

  • 如果一个 cookie 没有设置这两个参数中的任何一个,那么在关闭浏览器之后,它就会消失,此类 cookie 被称为 "session cookie”

  • 为了让 cookie 在浏览器关闭后仍然存在,需要设置 expiresmax-age 选项中的一个

    • expires:过期时间,将其设置为过去的时间,则 cookie 会被删除
    • max-age:过期时间距离当前时间的 数,将其设置为 0 或负数,则 cookie 会被删除
  • 日期必须完全采用 GMT 时区的这种格式。可以使用 date.toUTCString 来获取它

expires=Tue, 19 Jan 2038 03:14:07 GMT

// 当前时间 +1 天
let date = new Date(Date.now() + 86400e3);
date = date.toUTCString();
document.cookie = "user=yang; expires=" + date;

// cookie 会在一小时后失效
document.cookie = "user=yang; max-age=3600";

// 删除 cookie(让它立即过期)
document.cookie = "user=yang; max-age=0";

secure

设置 Cookie 应只能被通过 HTTPS 传输

  • 默认情况下 cookie 是基于域的,它们不区分协议
  • 使用此选项,如果一个 cookie 是通过 https://site.com 设置的,那么它不会在相同域的 HTTP 环境下出现
// 假设我们现在在 HTTPS 环境下
// 设置 cookie secure(只在 HTTPS 环境下可访问)
document.cookie = "user=yang; secure";

httpOnly

Web 服务器使用 Set-Cookie header 来设置 cookie,并且,它可以设置 httpOnly 选项

这个选项禁止任何 JavaScript 访问 cookie。使用 document.cookie 看不到此类 cookie,也无法对此类 cookie 进行操作

实用函数

当更新或删除一个 cookie 时,我们应该使用和设置 cookie 时相同的路径和域选项

/**
 * @param {Object} name 给定的 Cookie Name
 * 返回具有给定 name 的 cookie
 * 如果没找到,则返回 undefined
 * new RegExp 是动态生成的,以匹配 ; name=<value>
 * cookie 的值是经过编码的,所以 getCookie 使用了内建方法 decodeURIComponent 函数对其进行解码
 */
function getCookie(name) {
  let matches = document.cookie.match(new RegExp(
    "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
  ));
  return matches ? decodeURIComponent(matches[1]) : undefined;
}
/**
 * 将 cookie 的 name 设置为具有默认值 path=/(可以修改以添加其他默认值)和给定值 value
 */
function setCookie(name, value, options = {}) {

  options = {
    path: '/',
    // 如果需要,可以在这里添加其他默认值
    ...options
  };

  if (options.expires instanceof Date) {
    options.expires = options.expires.toUTCString();
  }

  let updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);

  for (let optionKey in options) {
    updatedCookie += "; " + optionKey;
    let optionValue = options[optionKey];
    if (optionValue !== true) {
      updatedCookie += "=" + optionValue;
    }
  }

  document.cookie = updatedCookie;
}

// 使用范例:
setCookie('user', 'John', {
  secure: true,
  'max-age': 3600
});

要删除一个 cookie,可以给它设置一个负的过期时间来调用它

function deleteCookie(name) {
  setCookie(name, "", {
    'max-age': -1
  })
}

Storage

Web 存储对象 localStoragesessionStorage 允许在浏览器上保存键/值对

在页面刷新后(对于 sessionStorage)甚至浏览器完全重启(对于 localStorage)后,数据仍然保留在浏览器中

  • 与 cookie 不同,Web 存储对象不会随每个请求被发送到服务器
  • 可以保存更多数据,大多数现代浏览器都允许保存至少 5MB 的数据(或更多),并且具有用于配置数据的设置
  • 服务器无法通过 HTTP header 操纵存储对象,一切都是在 JavaScript 中完成的
  • 存储绑定到源(域/协议/端口三者),不同协议或子域对应不同的存储对象,它们之间无法访问彼此数据
  • 键和值都必须是字符串,如果是任何其他类型,例数字或对象,它会被自动转换为字符串

区别

localStorage

  • 在同源的所有标签页和窗口之间共享数据
  • 数据不会过期,它在浏览器重启甚至系统重启后仍然存在

sessionStorage

  • 数据只存在于当前浏览器标签页
    • 具有相同页面的另一个标签页中将会有不同的存储
    • 在同一标签页下的 iframe 之间是共享的(假如它们来自相同的源)
  • 数据在页面刷新后仍然保留,但在关闭/重新打开浏览器标签页后不会被保留

方法、属性

两个存储对象都提供相同的方法和属性

  • setItem(key, value):存储键/值对
  • getItem(key):按照键获取值
  • removeItem(key):删除键及其对应的值
  • clear():删除所有数据
  • key(index):获取该索引下的键名
  • length:存储的内容的长度

遍历

// 方式一
for(let i = 0; i < localStorage.length; i++) {
  let key = localStorage.key(i);
  console.log(`${key}: ${localStorage.getItem(key)}`);
}

// 方式二
for(let key in localStorage) {
  if (!localStorage.hasOwnProperty(key)) {
    continue; // 跳过像 "setItem","getItem" 等这样的键
  }
  console.log(`${key}: ${localStorage.getItem(key)}`);
}

// 方式三
let keys = Object.keys(localStorage);
for(let key of keys) {
  alert(`${key}: ${localStorage.getItem(key)}`);
}

事件

localStoragesessionStorage 中的数据更新后,storage 事件就会触发(在调用 setItemremoveItemclear 方法后触发,将键作为对象属性来访问,不会触发 storage 事件)

该事件会在所有可访问到存储对象的 window 对象上触发,导致当前数据改变的 window 对象除外

  • event.key:发生更改的数据的 key(如果调用的是 .clear() 方法,则为 null
  • event.oldValue:旧值(如果是新增数据,则为 null
  • event.newValue:新值(如果是删除数据,则为 null
  • event.url:发生数据更新的文档的 url
  • event.storageArea:发生数据更新的 localStoragesessionStorage 对象

IndexedDB

【相关说明】open in new window 【MDN文档】open in new window

上次编辑于:
贡献者: sunzhenyang