阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > cookie操作

cookie操作

作者:陈川 阅读数:45674人阅读 分类: JavaScript

什么是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有一些限制需要注意:

  1. 每个域名下的Cookie数量有限制(通常50个左右)
  2. 每个Cookie的大小有限制(通常4KB)
  3. 总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;
// 发送到攻击者的服务器...

防范措施:

  1. 使用HttpOnly标志
  2. 对Cookie值进行编码
  3. 实现内容安全策略(CSP)

跨站请求伪造(CSRF)

攻击者可能利用用户的Cookie发起恶意请求。

防范措施:

  1. 使用SameSite属性
  2. 添加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大小

  1. 使用缩写或编码减少Cookie值大小
  2. 只存储必要的信息
// 存储最小必要数据
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的工具:

  1. Chrome: Application > Storage > Cookies
  2. Firefox: Storage > Cookies
  3. 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行为:

  1. 不同域名和子域名
  2. HTTPS和HTTP
  3. 不同路径
  4. 移动设备和桌面设备
// 测试跨子域名的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使用需要更加谨慎。

合规性检查

  1. 提供明确的Cookie使用说明
  2. 获取用户同意(非必要Cookie)
  3. 允许用户选择退出
// 简单的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();

隐私友好的替代方案

  1. 使用本地存储代替部分Cookie
  2. 减少跟踪Cookie的使用
  3. 提供匿名化选项
// 匿名用户标识方案
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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌