Cookie是浏览器提供的一种本地存储机制,属于BOM(Browser Object Model)的一部分。它允许网站在用户计算机上存储少量数据(通常不超过4KB),并在后续请求中将这些数据发送回服务器。
Cookie的特性
- 域名绑定:Cookie与特定域名绑定,只能由创建它的域名访问
- 有效期:可以设置过期时间,可以是会话级(浏览器关闭即删除)或持久性
- 路径限制:可以限制Cookie只在网站的特定路径下可用
- 安全标志:Secure标志确保Cookie只在HTTPS连接下传输
- HttpOnly:防止JavaScript访问,增强安全性防止XSS攻击
二、原生Cookie操作的问题
原生JavaScript通过document.cookie
操作Cookie存在以下问题:
- 接口不友好,需要手动拼接字符串
- 读取时需要解析整个cookie字符串
- 缺乏便捷的设置选项(如过期天数、路径等)
- 没有统一的错误处理机制
三、完整的Cookie封装方案
下面是一个完整的Cookie操作封装实现,解决了上述所有问题:
javascript
const Cookie = {
/**
* 设置Cookie
* @param {string} name - Cookie名称
* @param {string} value - Cookie值
* @param {Object} [options] - 配置选项
* @param {number} [options.expires] - 过期天数
* @param {string} [options.path] - 路径,默认为'/'
* @param {string} [options.domain] - 域名
* @param {boolean} [options.secure] - 是否仅HTTPS
* @param {boolean} [options.httpOnly] - 是否禁止JS访问
*/
set(name, value, options = {}) {
let cookieStr = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (options.expires) {
const date = new Date();
date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
cookieStr += `; expires=${date.toUTCString()}`;
}
cookieStr += `; path=${options.path || '/'}`;
if (options.domain) {
cookieStr += `; domain=${options.domain}`;
}
if (options.secure) {
cookieStr += '; secure';
}
if (options.httpOnly) {
cookieStr += '; HttpOnly';
}
document.cookie = cookieStr;
},
/**
* 获取Cookie
* @param {string} name - 要获取的Cookie名称
* @return {string|null} - Cookie值,不存在时返回null
*/
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;
},
/**
* 删除Cookie
* @param {string} name - 要删除的Cookie名称
* @param {string} [path] - 路径,默认为'/'
* @param {string} [domain] - 域名
*/
remove(name, path = '/', domain) {
this.set(name, '', {
expires: -1,
path,
domain
});
},
/**
* 检查Cookie是否存在
* @param {string} name - 要检查的Cookie名称
* @return {boolean} - 是否存在
*/
has(name) {
return this.get(name) !== null;
},
/**
* 获取所有Cookie名称
* @return {Array<string>} - Cookie名称数组
*/
keys() {
return document.cookie.split('; ').map(cookie => {
return decodeURIComponent(cookie.split('=')[0]);
});
}
};
四、封装方案的使用示例
1. 设置Cookie
javascript
// 设置会话Cookie
Cookie.set('username', 'john_doe');
// 设置7天后过期的Cookie
Cookie.set('preferences', 'dark_mode', { expires: 7 });
// 设置安全Cookie
Cookie.set('auth_token', 'abc123', { secure: true, httpOnly: true });
2. 获取Cookie
javascript
const username = Cookie.get('username');
console.log(username); // 输出: john_doe
3. 删除Cookie
javascript
Cookie.remove('preferences');
4. 检查Cookie是否存在
javascript
if (Cookie.has('session_id')) {
console.log('用户已登录');
}
5. 获取所有Cookie名称
javascript
const allCookies = Cookie.keys();
console.log(allCookies); // 输出: ['username', 'auth_token']
五、封装方案的进阶优化
1. 添加JSON支持
javascript
// 在set方法中添加
if (typeof value === 'object') {
value = JSON.stringify(value);
}
// 在get方法中添加
try {
const parsed = JSON.parse(decodedValue);
return parsed;
} catch (e) {
return decodedValue;
}
2. 添加默认配置
javascript
const Cookie = {
_defaultOptions: {
path: '/',
expires: 30, // 默认30天过期
secure: window.location.protocol === 'https:'
},
set(name, value, options = {}) {
const mergedOptions = { ...this._defaultOptions, ...options };
// 其余代码不变
}
// ...
};
3. 添加大小限制检查
javascript
set(name, value, options = {}) {
const cookieStr = `${name}=${value}`;
if (cookieStr.length > 4096) {
console.warn(`Cookie ${name} exceeds size limit of 4KB`);
return false;
}
// 其余设置代码
}
六、浏览器兼容性考虑
- 所有现代浏览器都支持基本的Cookie操作
- IE浏览器对Cookie大小限制更严格(每个Cookie不超过4095字节,每个域名不超过50个Cookie)
- 移动端浏览器对Cookie的支持可能有限,特别是在WebView中
- 第三方Cookie可能被浏览器阻止(如Safari的智能防跟踪功能)
七、安全最佳实践
- 敏感数据不要存储在Cookie中
- 始终对Cookie值进行编码/解码
- 为敏感Cookie设置Secure和HttpOnly标志
- 考虑使用SameSite属性防止CSRF攻击
- 定期轮换认证令牌
结语
本文提供的Cookie封装方案解决了原生API的诸多不便,提供了更友好、更安全的接口。在实际项目中,可以根据需要进一步扩展功能,如添加TypeScript类型定义、增加更详细的错误处理等。对于现代Web应用,也可以考虑结合localStorage、sessionStorage和IndexedDB等存储方案,根据数据特性选择最合适的存储方式。