详细讲解在 JavaScript 中如何使用 document.cookie 正确读取、写入 Cookie,并通过 Expires 与 Max-Age 设置过期时间与作用域,包含可复用的工具函数与常见注意事项。
JavaScript怎么读写Cookie并设置过期时间
时间:2026-10-30
浏览:275
文章目录
假设你在开发一个网页,需要保存用户选择的深色主题或提示弹窗的“今日不再显示”标记,并希望用户在关闭浏览器或数天后再打开时设置依然保留。此时使用 Cookie 进行本地状态标记是最直接的方案。在原生 JavaScript 中,所有对 Cookie 的操作均通过 document.cookie 接口完成,写入时赋值特定的键值指令串,并通过 max-age 或 expires 属性指定存活时长,读取时则需要对返回的聚合长字符串进行分割与反转义。
一、理解 document.cookie 的特殊访问机制
在 JavaScript 中操作 Cookie,最容易引起初学者困惑的是 document.cookie 的行为。它表面看起来是一个普通的字符串变量,但其实底层实现是一个特殊的访问器属性(getter/setter)。
当你向 document.cookie 赋值时,它并不会像普通变量那样直接覆盖现有的全部 Cookie。相反,它会解析你赋给它的这一小段指令,仅在浏览器存储池中新增或更新对应名称的单项 Cookie。而当你读取 document.cookie 时,浏览器会将当前页面域名和路径下所有未过期的键值对拼接在一起,以分号加空格(; )相连并返回一个长字符串,且所有存储属性(如有效路径、域名、过期时间等)都不会暴露在读取结果中。
二、写入 Cookie 并设置过期时间
如果不为写入的 Cookie 设置任何过期时间指令,浏览器默认会将其标记为“会话 Cookie”(Session Cookie)。这类 Cookie 仅保存在当前会话的内存中,一旦用户完全关闭浏览器,它就会被立即销毁。若要让 Cookie 持久化保存,必须显式指定过期时间。
1. 设置过期时间的两种标准语法
在 HTTP 及前端规范中,设置 Cookie 过期时间有两种方式:
max-age(推荐,相对时长):HTTP/1.1 引入的标准属性,单位为秒(Second)。例如max-age=3600表示当前写入后存活 1 小时;max-age=86400表示存活 1 天。当设为 0 或负数时,浏览器会立即将该 Cookie 移除。expires(传统标准,绝对时间):接受一个符合 GMT/UTC 格式的完整日期时间字符串(可由Date.prototype.toUTCString()生成)。例如expires=Thu, 01 Jan 2026 00:00:00 GMT。
max-age 和 expires,浏览器会严格以 max-age 为准。
2. 编写写入代码与关键参数
写入 Cookie 时,必须使用 encodeURIComponent 对键和值进行编码,避免等号、分号、空格或特殊字符破坏 Cookie 的基本格式语法。此外,强烈建议显式指定 path=/,确保整站根目录及各级子路径下均能正常共享访问该 Cookie,避免出现“在子页面写入却在首页无法读取”的路径隔离问题。
// 写入一个保存 7 天的 Cookie(使用现代标准的 max-age)
function setCookieWithMaxAge(name, value, days) {
const seconds = days * 24 * 60 * 60;
const encodedName = encodeURIComponent(name);
const encodedValue = encodeURIComponent(value);
// 拼接字符串并设置路径为根路径
document.cookie = `${encodedName}=${encodedValue}; max-age=${seconds}; path=/; SameSite=Lax`;
}
// 写入一个保存 7 天的 Cookie(使用传统兼容的 expires)
function setCookieWithExpires(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
const expiresUTC = date.toUTCString();
const encodedName = encodeURIComponent(name);
const encodedValue = encodeURIComponent(value);
document.cookie = `${encodedName}=${encodedValue}; expires=${expiresUTC}; path=/; SameSite=Lax`;
}
三、读取与解析 Cookie
读取 Cookie 时,document.cookie 返回的是一个简单的非结构化字符串,格式形如:
"theme=dark; user=alice%20smith; isLogged=true; notification_closed=1"
每个 Cookie 项之间使用一个分号紧随一个空格(; )分隔开。浏览器并不提供 document.cookie.getItem(name) 这样的原生对象式读取接口,因此开发者必须通过算法将这个长字符串拆分并检索。
解析步骤
- 空值校验:首先检查
document.cookie是否为空字符串。若未设置过 Cookie 或当前域名无可用项,则直接返回 null。 - 字符串切分:使用
split('; ')将长字符串分割为单条"key=value"的子串数组。 - 精确查找:遍历数组,使用
startsWith(name + '=')或indexOf('=')匹配指定的键名,避免部分匹配(例如查找id时误匹配到user_id)。 - 解码还原:截取等号后面的值部分,并调用
decodeURIComponent将其解码为原始文本。
四、封装生产可用的 Cookie 操作工具集
在日常项目中,直接频繁拼接字符串既繁琐又极易引入编码或作用域错误。以下是一套兼顾健壮性与现代标准的完整工具函数,支持设置过期天数、作用域路径、安全标记以及单项删除。
/**
* Cookie 操作工具集
*/
const CookieUtil = {
/**
* 设置 Cookie
* @param {string} name Cookie 名称
* @param {string} value Cookie 值
* @param {number} [days=7] 有效天数,设为 0 则为会话 Cookie
* @param {string} [path='/'] 作用域路径,默认为根目录
* @param {boolean} [secure=false] 是否仅允许 HTTPS 传输
*/
set(name, value, days = 7, path = '/', secure = false) {
let cookieStr = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; path=${path}; SameSite=Lax`;
if (typeof days === 'number' && days > 0) {
// 换算为秒数,现代浏览器优先使用 max-age
const maxAgeSeconds = Math.floor(days * 24 * 60 * 60);
cookieStr += `; max-age=${maxAgeSeconds}`;
// 同步提供 expires 以兼容极少数旧版浏览器引擎
const expireDate = new Date();
expireDate.setTime(expireDate.getTime() + days * 24 * 60 * 60 * 1000);
cookieStr += `; expires=${expireDate.toUTCString()}`;
}
if (secure) {
cookieStr += '; Secure';
}
document.cookie = cookieStr;
},
/**
* 获取指定名称的 Cookie 值
* @param {string} name Cookie 名称
* @returns {string|null} 匹配到的值,未找到返回 null
*/
get(name) {
if (!document.cookie) return null;
const prefix = `${encodeURIComponent(name)}=`;
const parts = document.cookie.split('; ');
for (let i = 0; i < parts.length; i++) {
const item = parts[i];
if (item.indexOf(prefix) === 0) {
const rawValue = item.substring(prefix.length);
try {
return decodeURIComponent(rawValue);
} catch (e) {
return rawValue; // 容错回退
}
}
}
return null;
},
/**
* 删除指定的 Cookie
* @param {string} name Cookie 名称
* @param {string} [path='/'] 创建时指定的路径
*/
delete(name, path = '/') {
// 核心原理:将 max-age 设为 0,并将 expires 设为过去的纪元时间
document.cookie = `${encodeURIComponent(name)}=; path=${path}; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
}
};
// 使用示例:
// 1. 设置一个存活 30 天的主题偏好
CookieUtil.set('theme', 'dark', 30);
// 2. 读取主题偏好
console.log(CookieUtil.get('theme')); // 输出: "dark"
// 3. 删除该配置
CookieUtil.delete('theme');
console.log(CookieUtil.get('theme')); // 输出: null
五、关键限制、安全策略与常见陷阱
在实际操作与维护 Cookie 时,还需要了解浏览器的底层限制与安全策略:
1. HttpOnly 属性的安全边界
由服务器在响应头(Set-Cookie: token=...; HttpOnly)中下发的 Cookie,拥有 HttpOnly 标记。这类 Cookie 受到浏览器的强保护,在客户端 JavaScript 的 document.cookie 中完全不可读、不可写、不可篡改。这是防范跨站脚本攻击(XSS)盗取用户身份凭证的黄金法则。因此,若发现某些认证 Cookie 无法在控制台打印或修改,并非代码逻辑出错,而是该 Cookie 属于 HttpOnly 属性。
2. 删除或覆盖时路径与域名不匹配
删除或更新一个已有 Cookie 时,指定的 path 和 domain 必须与当初创建该 Cookie 时的配置完全一致。如果最初在 /blog 路径下生成了一个 user=test,而在首页尝试用 path=/ 执行 max-age=0 进行删除,浏览器将视其为两个完全不同的 Cookie,导致旧的 Cookie 依然留在浏览器中。
3. 体积与数量配额限制
单个 Cookie 的总大小(包含键、值与所有属性字符串)通常不得超过 4KB(约 4096 字节)。同时,浏览器对单个域名下的 Cookie 数量通常限制在 20 到 50 个之间。若超出配额,旧的 Cookie 会被浏览器静默淘汰。因此,对于长文本、大量本地缓存数据或复杂对象,应优先使用 localStorage 或 IndexedDB,而非挤压 Cookie 空间。
六、总结
在 JavaScript 中管理 Cookie 的核心要点可以概括为:
- 写入是增量修改:赋值给
document.cookie仅改变指定键名项,不会抹去已有的其他 Cookie。 - 过期时间控制:设置长期有效时,推荐使用
max-age=秒数,搭配expires=UTC字符串获得最佳兼容;删除 Cookie 时将max-age设为0。 - 路径必须显式:大部分业务场景中建议添加
path=/,确保全局互通,并在删除时使用相同路径。 - 安全意识:涉及敏感登录状态的凭证应始终交由服务端设置
HttpOnly与Secure,普通轻量偏好设置才适合在前端由 JavaScript 自由读写。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。