document.cookie 是一个字符串 API,“设置有效期”其实就是在 cookie 字符串里追加 expires 或 max-age 属性。
规则很简单:不写有效期 = 会话 cookie(浏览器关掉就没)、写了 = 持久化 cookie。
方式一:expires(老写法)
传一个 UTC 时间字符串:
const d = new Date();
d.setTime(d.getTime() + 7 * 24 * 60 * 60 * 1000); // 7 天
document.cookie = `token=abc; expires=${d.toUTCString()}; path=/`;
注意必须是 toUTCString(),用 toString() 或 toISOString() 会挂。
方式二:max-age(现代推荐)
直接指定”多少秒后过期”:
document.cookie = `token=abc; max-age=${7 * 24 * 60 * 60}; path=/`;
单位是秒。max-age 更直观,也不用管时区。老到 IE 那一档才要考虑 expires。
删除 cookie
本质就是”立刻过期”:
document.cookie = "token=; max-age=0; path=/";
// 或
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
三个删不掉的坑
1. path 不一致
创建时用 path=/,删除也必须带上 path=/。不带就等于删的是当前路径下的 cookie,很可能和实际存放的 cookie 不是同一个。
2. domain 不一致
.example.com 和 sub.example.com 是两条不同的 cookie。删除时必须匹配写入时的 domain。
3. HttpOnly cookie 前端改不了
服务端设置了 HttpOnly 的 cookie,document.cookie 完全读不到、也删不掉。只能后端接口去清。
封装模板
前端项目里放一份省心:
export function setCookie(name, value, days = 7, options = {}) {
const d = new Date();
d.setTime(d.getTime() + days * 864e5); // 864e5 = 24*60*60*1000
const parts = [
`${name}=${encodeURIComponent(value)}`,
`expires=${d.toUTCString()}`,
`path=${options.path || "/"}`,
];
if (options.domain) parts.push(`domain=${options.domain}`);
if (options.secure) parts.push("secure");
if (options.sameSite) parts.push(`samesite=${options.sameSite}`);
document.cookie = parts.join("; ");
}
export function getCookie(name) {
return document.cookie
.split("; ")
.find(row => row.startsWith(name + "="))
?.split("=")[1];
}
export function deleteCookie(name, options = {}) {
setCookie(name, "", -1, options); // 复用同样的 path/domain
}
上生产别忘的属性
正经站点几乎必配的三个属性:
Secure:只走 HTTPSSameSite=Lax(登录态用Strict更安全)HttpOnly(防 XSS 盗 token,只能后端 Set-Cookie 时写)
前端能设的就 Secure 和 SameSite,HttpOnly 必须走服务端。
一句话总结
现代写法用 max-age、删除记得带 path=/、跨域跨子域记得对齐 domain。真安全靠 HttpOnly + Secure + SameSite,那部分归后端管。
