数据存储
Cookie
是直接存储在浏览器中的一小串数据
通常由 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 在浏览器关闭后仍然存在,需要设置
expires
或max-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 时相同的路径和域选项
获取 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
/**
* 将 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
要删除一个 cookie,可以给它设置一个负的过期时间来调用它
function deleteCookie(name) {
setCookie(name, "", {
'max-age': -1
})
}
Storage
Web 存储对象
localStorage
和sessionStorage
允许在浏览器上保存键/值对在页面刷新后(对于
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)}`);
}
事件
当
localStorage
或sessionStorage
中的数据更新后,storage
事件就会触发(在调用setItem
,removeItem
,clear
方法后触发,将键作为对象属性来访问,不会触发storage
事件)该事件会在所有可访问到存储对象的
window
对象上触发,导致当前数据改变的window
对象除外
event.key
:发生更改的数据的key
(如果调用的是.clear()
方法,则为null
)event.oldValue
:旧值(如果是新增数据,则为null
)event.newValue
:新值(如果是删除数据,则为null
)event.url
:发生数据更新的文档的 urlevent.storageArea
:发生数据更新的localStorage
或sessionStorage
对象