cookie操作
什么是Cookie
Cookie是存储在用户本地终端上的小型文本数据,由服务器发送到浏览器并保存在本地。它主要用于记录用户状态、存储用户偏好或跟踪用户行为。Cookie通常由键值对构成,每个Cookie还包含域名、路径、过期时间等属性。
// 一个典型的Cookie示例
document.cookie = "username=JohnDoe; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/";
Cookie的基本操作
设置Cookie
在JavaScript中,可以通过直接赋值给document.cookie来设置Cookie。设置时需要指定名称和值,还可以添加其他可选属性。
// 设置一个简单的Cookie
document.cookie = "theme=dark";
// 设置带过期时间的Cookie
const date = new Date();
date.setTime(date.getTime() + (7 * 24 * 60 * 60 * 1000)); // 7天后过期
document.cookie = `user_token=abc123; expires=${date.toUTCString()}`;
// 设置带路径的Cookie
document.cookie = "preferences=font_large; path=/settings";
读取Cookie
读取所有Cookie可以通过document.cookie属性,它会返回当前域名下所有Cookie的字符串,格式为"name=value; name2=value2"。
// 获取所有Cookie
const allCookies = document.cookie;
console.log(allCookies); // "theme=dark; user_token=abc123; preferences=font_large"
// 获取特定Cookie的函数
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.split('=');
if (cookieName === name) {
return decodeURIComponent(cookieValue);
}
}
return null;
}
const theme = getCookie('theme'); // "dark"
删除Cookie
删除Cookie实际上是通过设置一个已过期的Cookie来实现的。
// 删除Cookie
document.cookie = "theme=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
// 通用的删除Cookie函数
function deleteCookie(name, path = '/') {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`;
}
deleteCookie('user_token');
Cookie的属性详解
过期时间(expires/max-age)
控制Cookie的生存周期,可以是具体的日期(expires)或秒数(max-age)。
// 使用expires设置过期时间
const expiresDate = new Date();
expiresDate.setDate(expiresDate.getDate() + 30);
document.cookie = `promo_shown=1; expires=${expiresDate.toUTCString()}`;
// 使用max-age设置过期时间(秒)
document.cookie = "session_id=xyz789; max-age=3600"; // 1小时后过期
路径(path)
指定Cookie可用的URL路径前缀,默认为当前路径。
// 只在/admin路径下可用的Cookie
document.cookie = "admin_token=secret; path=/admin";
// 全站可用的Cookie
document.cookie = "language=en; path=/";
域名(domain)
指定Cookie可用的域名,默认为当前域名。
// 主域名和所有子域名都可用的Cookie
document.cookie = "shared_id=123; domain=.example.com";
// 仅特定子域名可用的Cookie
document.cookie = "subdomain_data=abc; domain=shop.example.com";
安全标志(Secure)
标记为Secure的Cookie只能通过HTTPS协议传输。
// 安全Cookie
document.cookie = "auth_token=secure123; Secure";
HttpOnly标志
防止JavaScript访问,只能由服务器通过HTTP响应头设置。
Set-Cookie: session=abc123; HttpOnly
Cookie的限制
浏览器对Cookie有一些限制需要注意:
- 每个域名下的Cookie数量有限制(通常50个左右)
- 每个Cookie的大小有限制(通常4KB)
- 总Cookie大小有限制(不同浏览器不同)
// 测试Cookie大小限制的函数
function testCookieSizeLimit() {
let size = 0;
const cookieName = 'size_test';
try {
while (true) {
size += 100;
const value = 'a'.repeat(size);
document.cookie = `${cookieName}=${value}`;
if (!document.cookie.includes(cookieName)) break;
}
} catch (e) {
console.error(e);
} finally {
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;
}
return size - 100;
}
const maxSize = testCookieSizeLimit();
console.log(`Max cookie size: ${maxSize} characters`);
实际应用示例
用户偏好设置
// 保存用户主题偏好
function saveThemePreference(theme) {
const expires = new Date();
expires.setFullYear(expires.getFullYear() + 1);
document.cookie = `user_theme=${theme}; expires=${expires.toUTCString()}; path=/`;
}
// 加载保存的主题
function loadThemePreference() {
const theme = getCookie('user_theme');
if (theme) {
document.documentElement.setAttribute('data-theme', theme);
}
}
// 切换主题
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', newTheme);
saveThemePreference(newTheme);
}
购物车功能
// 添加到购物车
function addToCart(productId, quantity = 1) {
const cart = getCart();
cart[productId] = (cart[productId] || 0) + quantity;
saveCart(cart);
}
// 从购物车移除
function removeFromCart(productId) {
const cart = getCart();
delete cart[productId];
saveCart(cart);
}
// 获取购物车内容
function getCart() {
const cartCookie = getCookie('shopping_cart');
return cartCookie ? JSON.parse(cartCookie) : {};
}
// 保存购物车
function saveCart(cart) {
const expires = new Date();
expires.setDate(expires.getDate() + 7);
document.cookie = `shopping_cart=${JSON.stringify(cart)}; expires=${expires.toUTCString()}; path=/`;
}
Cookie的安全考虑
跨站脚本攻击(XSS)
由于Cookie可以被JavaScript访问,容易受到XSS攻击。
// 恶意脚本可能窃取Cookie
const stolenCookies = document.cookie;
// 发送到攻击者的服务器...
防范措施:
- 使用HttpOnly标志
- 对Cookie值进行编码
- 实现内容安全策略(CSP)
跨站请求伪造(CSRF)
攻击者可能利用用户的Cookie发起恶意请求。
防范措施:
- 使用SameSite属性
- 添加CSRF令牌
// 设置SameSite属性
document.cookie = "session_id=abc123; SameSite=Lax";
// 或者更严格的SameSite=Strict
document.cookie = "sensitive_data=xyz; SameSite=Strict; Secure";
敏感数据存储
避免在Cookie中存储敏感信息,如密码、信用卡号等。
// 不安全的做法
document.cookie = `password=${userPassword}`;
// 更好的做法是存储会话ID
document.cookie = `session_id=${generateSecureToken()}; Secure; HttpOnly; SameSite=Strict`;
Cookie的替代方案
虽然Cookie有很多用途,但在某些场景下可能有更好的替代方案:
Web Storage API
// localStorage - 持久化存储
localStorage.setItem('user_settings', JSON.stringify(settings));
const settings = JSON.parse(localStorage.getItem('user_settings'));
// sessionStorage - 会话级存储
sessionStorage.setItem('temp_data', 'value');
const tempData = sessionStorage.getItem('temp_data');
IndexedDB
适合存储大量结构化数据。
// 打开或创建数据库
const request = indexedDB.open('myDatabase', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('products', { keyPath: 'id' });
};
request.onsuccess = (event) => {
const db = event.target.result;
const transaction = db.transaction('products', 'readwrite');
const store = transaction.objectStore('products');
// 添加数据
store.add({ id: 1, name: 'Product 1', price: 9.99 });
// 获取数据
const getRequest = store.get(1);
getRequest.onsuccess = () => {
console.log(getRequest.result);
};
};
现代Cookie管理
Cookie的批量操作
处理多个Cookie时,可以创建实用函数:
class CookieManager {
static set(name, value, options = {}) {
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (options.expires instanceof Date) {
cookie += `; expires=${options.expires.toUTCString()}`;
}
if (options.maxAge) {
cookie += `; max-age=${options.maxAge}`;
}
if (options.path) {
cookie += `; path=${options.path}`;
}
if (options.domain) {
cookie += `; domain=${options.domain}`;
}
if (options.secure) {
cookie += '; Secure';
}
if (options.sameSite) {
cookie += `; SameSite=${options.sameSite}`;
}
document.cookie = cookie;
}
static get(name) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [cookieName, cookieValue] = cookie.split('=');
if (decodeURIComponent(cookieName) === name) {
return decodeURIComponent(cookieValue);
}
}
return null;
}
static delete(name, path = '/') {
this.set(name, '', {
expires: new Date(0),
path
});
}
static getAll() {
const cookies = {};
document.cookie.split('; ').forEach(cookie => {
const [name, value] = cookie.split('=');
cookies[decodeURIComponent(name)] = decodeURIComponent(value);
});
return cookies;
}
}
// 使用示例
CookieManager.set('user', 'john', {
maxAge: 3600,
path: '/',
sameSite: 'Lax'
});
const user = CookieManager.get('user');
CookieManager.delete('user');
Cookie与框架集成
在React、Vue等现代框架中使用Cookie:
// React示例 - 使用高阶组件管理Cookie
function withCookies(WrappedComponent) {
return class extends React.Component {
setCookie = (name, value, options) => {
CookieManager.set(name, value, options);
};
getCookie = (name) => {
return CookieManager.get(name);
};
deleteCookie = (name, path) => {
CookieManager.delete(name, path);
};
render() {
return (
<WrappedComponent
{...this.props}
setCookie={this.setCookie}
getCookie={this.getCookie}
deleteCookie={this.deleteCookie}
/>
);
}
};
}
// 使用高阶组件
class UserPreferences extends React.Component {
componentDidMount() {
const theme = this.props.getCookie('theme') || 'light';
this.setState({ theme });
}
handleThemeChange = (theme) => {
this.props.setCookie('theme', theme, { maxAge: 365 * 24 * 3600 });
this.setState({ theme });
};
render() {
// ...
}
}
export default withCookies(UserPreferences);
Cookie的性能优化
大量或过大的Cookie会影响页面性能,特别是在每个HTTP请求中都会携带。
减少Cookie大小
- 使用缩写或编码减少Cookie值大小
- 只存储必要的信息
// 存储最小必要数据
const userData = {
id: 123,
// 而不是存储整个用户对象
};
document.cookie = `user=${JSON.stringify(userData)}`;
使用CDN域名分离Cookie
静态资源使用无Cookie的域名。
<!-- 主域名可能设置Cookie -->
<img src="https://www.example.com/tracker.gif">
<!-- 静态资源使用无Cookie的CDN -->
<img src="https://cdn.example.com/logo.png">
定期清理过期Cookie
// 清理过期Cookie的函数
function cleanUpCookies() {
const cookies = document.cookie.split('; ');
const now = new Date();
cookies.forEach(cookie => {
const [name, ...parts] = cookie.split('=');
const cookieStr = parts.join('=');
// 检查过期时间
const expiresMatch = cookieStr.match(/expires=([^;]+)/i);
if (expiresMatch) {
const expiresDate = new Date(expiresMatch[1]);
if (expiresDate < now) {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
}
}
});
}
// 页面加载时执行清理
cleanUpCookies();
Cookie的调试与测试
浏览器开发者工具
现代浏览器都提供了查看和操作Cookie的工具:
- Chrome: Application > Storage > Cookies
- Firefox: Storage > Cookies
- Safari: Storage > Cookies
单元测试Cookie操作
使用测试框架测试Cookie相关代码:
// 使用Jest测试Cookie操作
describe('CookieManager', () => {
beforeEach(() => {
// 测试前清除所有Cookie
document.cookie.split('; ').forEach(cookie => {
const [name] = cookie.split('=');
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;
});
});
test('should set and get cookie', () => {
CookieManager.set('test', 'value');
expect(CookieManager.get('test')).toBe('value');
});
test('should delete cookie', () => {
CookieManager.set('test', 'value');
CookieManager.delete('test');
expect(CookieManager.get('test')).toBeNull();
});
test('should handle special characters', () => {
const value = '测试&value=123';
CookieManager.set('special', value);
expect(CookieManager.get('special')).toBe(value);
});
});
真实场景测试
在不同环境下测试Cookie行为:
- 不同域名和子域名
- HTTPS和HTTP
- 不同路径
- 移动设备和桌面设备
// 测试跨子域名的Cookie共享
function testCrossSubdomainCookie() {
// 在主域名设置Cookie
document.cookie = "cross_domain=test; domain=.example.com; path=/";
// 在子域名检查是否可用
fetch('https://sub.example.com/check-cookie')
.then(response => response.json())
.then(data => console.log('Cookie available on subdomain:', data.hasCookie));
}
Cookie与隐私法规
随着GDPR等隐私法规的实施,Cookie使用需要更加谨慎。
合规性检查
- 提供明确的Cookie使用说明
- 获取用户同意(非必要Cookie)
- 允许用户选择退出
// 简单的Cookie同意横幅实现
class CookieConsent {
constructor() {
if (!this.getConsent()) {
this.showBanner();
}
}
showBanner() {
const banner = document.createElement('div');
banner.innerHTML = `
<div class="cookie-banner">
<p>我们使用Cookie来提升您的体验。继续即表示您同意我们的Cookie政策。</p>
<button id="accept-cookies">接受</button>
<button id="reject-cookies">拒绝</button>
<a href="/cookie-policy">了解更多</a>
</div>
`;
document.body.appendChild(banner);
document.getElementById('accept-cookies').addEventListener('click', () => {
this.setConsent(true);
banner.remove();
});
document.getElementById('reject-cookies').addEventListener('click', () => {
this.setConsent(false);
this.deleteNonEssentialCookies();
banner.remove();
});
}
setConsent(given) {
localStorage.setItem('cookie_consent', given ? 'true' : 'false');
if (given) {
document.cookie = "cookie_consent=true; max-age=31536000; path=/";
}
}
getConsent() {
return localStorage.getItem('cookie_consent') === 'true' ||
document.cookie.includes('cookie_consent=true');
}
deleteNonEssentialCookies() {
// 删除所有非必要Cookie
const essentialCookies = ['session_id', 'csrf_token'];
document.cookie.split('; ').forEach(cookie => {
const [name] = cookie.split('=');
if (!essentialCookies.includes(name)) {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;
}
});
}
}
// 初始化
new CookieConsent();
隐私友好的替代方案
- 使用本地存储代替部分Cookie
- 减少跟踪Cookie的使用
- 提供匿名化选项
// 匿名用户标识方案
function getAnonymousUserId() {
let userId = localStorage.getItem('anonymous_user_id');
if (!userId) {
userId = generateUUID(); // 生成随机ID
localStorage.setItem('anonymous_user_id', userId);
}
return userId;
}
// 而不是使用识别性强的Cookie
// document.cookie = "user_id
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn