Cookie
用于维持 HTTP 请求之间的关系:
浏览器向服务器发送请求,服务器可以把用户信息存放到响应头 set-cookie
上。浏览器接收到响应后,会自动读取 set-cookie
并更新 Cookie。随后浏览器发起的所有请求,都会自动把当前域名下所有未过期的 Cookie 存放到请求头 cookie
上。服务器接收到请求后,可以解析请求头 cookie
,以获取用户信息。这样,请求之间就关联起来了。
Cookie 的基本用法
- 获取所有 Cookie:
console.log(document.cookie); // "name=superman; age=18"
- 添加 / 更新指定 Cookie:
document.cookie = 'gender=male';
console.log(document.cookie); // "name=superman; age=18; gender=male"
Cookie 的可选属性
-
Domain
:Cookie 生效的域名;默认为当前域名。 -
Path
:Cookie 生效的路径;默认为/
,表示当前域名下的所有路径都可以访问该 Cookie。 -
Expires
/Max-Age
:Cookie 的有效期;默认为Session
,表示浏览器关闭后失效。
Expires
为指定时间;Max-Age
为相对时间,单位为 s,优先级比Expires
高。 -
HttpOnly
:禁止 JS 访问 Cookie。默认可以通过 JS 访问(只能通过服务端设置) -
Secure
:设置 Cookie 只能通过 HTTPS 传输。默认可以通过 HTTP(S) 传输(只能通过服务端设置) -
SameSite
:控制 Cookie 的跨站点行为。可以设置为Strict
、Lax
或None
(只能通过服务端设置)Strict
:完全禁止第三方 Cookie。如果当前网页是一个第三方网页,那么只有从当前网页的 URL 访问的 Cookie 才会被发送。Lax
:禁止跨站点的 POST 请求发送 Cookie,但允许同站点的 POST 请求发送 Cookie。None
:允许第三方 Cookie。
const expires = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30);
document.cookie = `name=superman; expires=${expires}`; // 30 天后失效
document.cookie = 'age=23; max-age=30'; // 30s 后失效
document.cookie = 'gender=male; path=/user'; // 只在 /user 路径或其子路径下生效
Cookie 的限制
为了避免存储过多的 Cookie 数据而导致浏览器性能下降和隐私问题,浏览器对于一个域名下可以存放的 Cookie 数量都有限制,一般在 50 个左右。当达数量达到上限时,浏览器会自动清除以前的 Cookie。不同浏览器的清除行为可能不一样,或清除最旧的 Cookie,或清除最久未使用的 Cookie。
浏览器对于每个 Cookie 的大小也有限制,一般在 4KB 左右。当 Cookie 的大小超过浏览器的限制时,浏览器会自动截断 Cookie 的数据。
WebStorage
用于存储数据。
- 以 key-value 的形式存储在浏览器中。
- key-value 的 key 和 value 都只能是 [字符串],对于非字符串数据,浏览器会尝试将其转为字符串。
- 如果读取的 key 不存在,读取到的 value 会为
null
;JSON.parse(null)
返回null
。 - 对 WebStorage 的操作属于同步操作。
SessionStorage
console.log(sessionStorage); // 打印 SessionStorage 对象
sessionStorage.setItem('name', 'superman'); // 存数据
const name = sessionStorage.getItem('name'); // 取数据
sessionStorage.removeItem('name'); // 删除数据
sessionStorage.clear(); // 清空数据
LocalStorage
console.log(localStorage); // 打印 LocalStorage 对象
localStorage.setItem('name', 'superman'); // 存数据
const name = localStorage.getItem('name'); // 取数据
localStorage.removeItem('name'); // 删除数据
localStorage.clear(); // 清空数据
搜索的历史记录、购物车等数据一般都存放在 LocalStorage。
监听 LocalStorage 的变化:
// 监听 storage 事件
window.addEventListener('storage', function (e) {
if (e.key === 'myData') {
// localStorage 的 'myData' 发生变化
console.log('localStorage 中的 myData 发生了变化:', e.newValue);
}
});
document.querySelector('.local_storage').addEventListener('click', (e) => {
// 点击按钮时, 将 'myData' 的值设置为当前时间
localStorage.setItem('myData', Date.now());
});
e.key
:发生变化的 key。e.oldValue
:变化前的值。e.newValue
:变化后的值。e.storageArea
:发生变化的 Storage 对象。e.url
:发生变化的 Storage 对象所属的文档的 URL。
注意:这个事件是在其他窗口或标签页中对同一域的 LocalStorage 进行更改时触发的。
demo:
/**
* 发送消息
* @param {String} type 消息类型
* @param {*} payload 消息内容
*/
export function sendMsg(type, payload) {
localStorage.setItem(
`@@:${type}`,
JSON.stringify({ payload, time: Date.now() })
);
}
/**
* 监听消息
* @param {Function} handler 消息处理函数
* @returns {Function} 取消监听的函数
*/
export function listenMsg(handler) {
const storageHandler = (e) => {
const { key, newValue } = e;
if (key.startsWith('@@:')) {
const type = key.replace('@@:', '');
handler({ type, payload: JSON.parse(newValue).payload });
}
};
window.addEventListener('storage', storageHandler);
return () => {
window.removeEventListener('storage', storageHandler);
};
}
使用:
// 发送消息
sendMsg('msg', 'hello');
// 监听消息
const cancel = listenMsg(({ type, payload }) => {
console.log(type, payload);
});
// 取消监听
cancel();
Cookie & WebStorage
存储大小
- Cookie:大约 4K。
- WebStorage:大约 5M。
通信
- Cookie:能在浏览器与服务器之间来回传递。
- WebStorage:不参与通信。
作用域
- Cookie:在同源窗口中共享。
- SessionStorage:仅在当前标签页可用。
但是在某些特定场景下新开的页面会复制之前页面的 SessionStorage,比如使用a
标签或window.open
新开页面。 - LocalStorage:在同源窗口中共享。
- 同源:协议、域名、端口号都一样;不一样则为跨域。
数据有效期
- Cookie:默认情况下,关闭浏览器则失效;可以设置失效时间。
- SessionStorage:关闭标签页则失效。
- LocalStorage:永久有效。