1. 项目概述:为什么我们还在聊Cookie操作?
在Web开发的世界里,Cookie就像是一个老派的、但依然不可或缺的“记事本”。尽管现代前端有了LocalStorage、SessionStorage甚至IndexedDB这些更强大的本地存储方案,但Cookie凭借其与生俱来的、由浏览器自动管理的HTTP请求头携带能力,在处理用户会话(Session)、身份认证令牌以及一些简单的用户偏好设置时,依然占据着不可替代的位置。尤其是在处理需要与服务器端紧密交互的场景,比如保持登录状态、实现跨页面数据传递,Cookie的“自动提交”特性是其他存储API无法比拟的。
我见过不少新手开发者,一上来就直奔Vue、React这些框架,却对基础的Cookie操作一知半解。等到真正需要处理登录逻辑、或者对接一个老旧的第三方服务时,面对document.cookie那略显原始的字符串操作,往往一头雾水。实际上,无论是直接使用原生的document.cookie,还是借助像js-cookie这样的轻量级库,掌握Cookie的增删改查都是前端工程师的一项基本功。它不复杂,但细节很多,一个字符的错误就可能导致整个认证流程失败。今天,我就结合自己多年的踩坑经验,系统性地整理一下JavaScript中操作Cookie的常见API、核心原理以及那些容易被忽略的“魔鬼细节”。
2. Cookie核心原理与属性全解析
在动手写代码之前,我们必须先理解Cookie到底是什么,以及它身上那些关键的属性都控制着什么。这能帮你从根本上避免很多低级错误。
2.1 Cookie的本质与数据格式
Cookie本质上是一段小型文本数据,由服务器通过Set-Cookie响应头发送给浏览器,或者由客户端JavaScript通过document.cookie设置。浏览器会将这些数据存储起来,并在后续向同一域名发送的HTTP请求中,自动通过Cookie请求头将其携带回服务器。
一个Cookie字符串的格式是这样的:name=value; expires=Sat, 01 Jan 2025 00:00:00 GMT; path=/; domain=.example.com; secure; samesite=lax
我们来拆解每一个部分:
name=value:这是核心的键值对。name和value都必须是字符串。这里有一个非常重要的点:value中不能包含分号(;)、逗号(,)和空格。如果必须包含,请使用encodeURIComponent()进行编码,读取时再用decodeURIComponent()解码。expires和max-age:控制Cookie的生命周期。expires指定一个具体的GMT格式的过期时间点。如果未设置或设置为一个过去的时间,Cookie会在会话结束时(关闭浏览器)失效,这被称为“会话Cookie”。max-age指定Cookie从设置开始存活的秒数,优先级高于expires。例如max-age=2592000表示存活30天。
path:指定Cookie在哪些路径下可以被发送。默认为设置Cookie时的页面路径。例如,path=/admin的Cookie只有在访问/admin及其子路径(如/admin/users)时才会被发送。通常我们会设置为path=/,使其在整个站点下有效。domain:指定Cookie对哪个域名有效。默认为当前域名,不包含子域名。如果你希望Cookie在a.example.com和b.example.com之间共享,需要显式设置为domain=.example.com(注意前面的点)。这是一个常见的跨子域共享配置点。secure:这是一个布尔标志。如果设置,Cookie只会在通过HTTPS协议发送请求时才会被携带。在当今全站HTTPS的趋势下,对于涉及认证的Cookie,设置secure是必须的安全实践。samesite:这是一个相对较新但至关重要的安全属性,用于控制跨站请求时是否发送Cookie。Strict:最严格,完全禁止第三方(跨站)请求携带Cookie。用户从外部链接点击进入你的网站,登录态Cookie也不会被发送。Lax(默认值,现代浏览器的默认行为):允许在顶级导航(如点击链接)和GET请求中携带Cookie,但禁止在跨站的POST提交、iframe加载或通过fetch/XMLHttpRequest发起的请求中携带。这平衡了安全性和用户体验。None:允许跨站携带Cookie,但必须同时设置secure属性(即必须使用HTTPS)。常用于需要跨站共享登录态的第三方服务。
注意:
samesite属性在现代浏览器中已成为默认Lax。如果你的应用依赖跨站POST请求携带Cookie(例如一个传统的、嵌入在第三方页面的表单),你需要明确设置samesite=none; secure,并确保你的站点是HTTPS的,否则请求将丢失Cookie导致会话失效。这是我排查过最多的“诡异”登录问题之一。
2.2 原生API:document.cookie的双重角色
document.cookie是一个有趣的属性,它同时扮演了“读”和“写”两个角色,但行为完全不同。
写入(设置/修改): 当你给document.cookie赋值一个字符串时,你并不是在替换所有Cookie,而是在新增或更新一个特定的Cookie。
// 设置一个名为“username”的Cookie,值为“john”,路径为根目录,7天后过期 const days = 7; const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); document.cookie = `username=john; expires=${date.toUTCString()}; path=/`;写入操作是精细化的,一次只影响一个键值对。
读取(获取): 当你读取document.cookie时,它会返回当前页面可访问的所有Cookie,格式是一个长长的字符串,所有Cookie用分号和空格(;)连接。
console.log(document.cookie); // 输出可能为:"username=john; theme=dark; session_id=abc123"读取操作是粗粒度的,你得到的是一个需要自行解析的字符串。这种设计导致了原生API操作的不便,也是封装库存在的主要价值。
3. 从零封装一个健壮的Cookie工具库
理解了原理,我们就可以动手封装自己的工具函数了。这个过程能让你对每一个细节都了如指掌。我将按照“增、删、改、查”的逻辑来构建。
3.1 基础工具函数:编码与日期处理
在开始核心功能前,我们需要两个辅助函数。
/** * 安全地编码Cookie值,主要处理分号、逗号和空格。 * @param {string} value - 原始值 * @returns {string} 编码后的值 */ function encodeCookieValue(value) { // 使用encodeURIComponent可以安全地处理绝大多数特殊字符 // 注意:它也会编码一些在Cookie值中合法的字符,如‘=’,但这通常是安全的。 return encodeURIComponent(value); } /** * 解码Cookie值 * @param {string} value - 编码后的值 * @returns {string} 解码后的原始值 */ function decodeCookieValue(value) { try { return decodeURIComponent(value); } catch (e) { // 如果解码失败(例如值未被编码),则返回原值 return value; } } /** * 将天数转换为GMT格式的过期时间字符串 * @param {number} days - 过期天数 * @returns {string} GMT格式的日期字符串 */ function getExpiresDate(days) { const date = new Date(); date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); return date.toUTCString(); }3.2 核心操作一:设置Cookie(增/改)
设置Cookie需要考虑所有可选属性,并确保值的编码安全。
/** * 设置一个Cookie * @param {string} name - Cookie名称 * @param {string} value - Cookie值 * @param {Object} [options] - 配置选项 * @param {number} [options.expires] - 过期天数 * @param {string} [options.expiresDate] - 具体的GMT过期时间字符串(优先级高于expires) * @param {string} [options.path] - 路径,默认'/' * @param {string} [options.domain] - 域名 * @param {boolean} [options.secure] - 是否仅HTTPS * @param {'Strict'|'Lax'|'None'} [options.sameSite] - SameSite属性 */ function setCookie(name, value, options = {}) { let cookieString = `${encodeCookieValue(name)}=${encodeCookieValue(value)}`; // 处理过期时间 if (options.expiresDate) { cookieString += `; expires=${options.expiresDate}`; } else if (options.expires) { cookieString += `; expires=${getExpiresDate(options.expires)}`; } // 如果都不设置,则为会话Cookie // 处理路径 cookieString += `; path=${options.path || '/'}`; // 处理域名 if (options.domain) { cookieString += `; domain=${options.domain}`; } // 处理Secure if (options.secure) { cookieString += '; secure'; } // 处理SameSite if (options.sameSite) { const sameSiteLower = options.sameSite.toLowerCase(); if (['strict', 'lax', 'none'].includes(sameSiteLower)) { cookieString += `; samesite=${sameSiteLower}`; // 重要:如果设置为None,必须同时设置Secure(在HTTPS下) if (sameSiteLower === 'none' && !options.secure) { console.warn(`Cookie "${name}"设置了samesite=None但未设置secure,在现代浏览器中可能无效。`); } } } // 执行设置 document.cookie = cookieString; } // 使用示例 setCookie('user_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', { expires: 7, // 7天后过期 path: '/', secure: true, // 仅HTTPS sameSite: 'Lax' });3.3 核心操作二:读取Cookie(查)
读取需要从document.cookie的长字符串中解析出我们需要的特定值。
/** * 获取指定名称的Cookie值 * @param {string} name - 要查找的Cookie名称 * @returns {string|null} - 找到则返回值,未找到返回null */ function getCookie(name) { // 1. 获取所有Cookie字符串 const allCookies = document.cookie; if (!allCookies) { return null; } // 2. 按‘; ’分割成单个Cookie键值对 const cookiePairs = allCookies.split('; '); // 3. 遍历查找 for (const pair of cookiePairs) { const [cookieName, cookieValue] = pair.split('='); // 解码名称进行比较(因为名称也可能被编码,尽管不常见) if (decodeCookieValue(cookieName) === name) { // 找到后解码值并返回 return decodeCookieValue(cookieValue); } } // 4. 未找到 return null; } // 使用示例 const token = getCookie('user_token'); if (token) { console.log('获取到Token:', token); // 通常这里会将token放入后续API请求的Authorization头中 } else { console.log('用户未登录或Token已过期'); }3.4 核心操作三:删除Cookie
JavaScript中没有直接删除Cookie的API。删除的本质是设置一个同名的Cookie,并将其过期时间设置为一个过去的时间。同时,path和domain必须与要删除的Cookie创建时保持一致,否则删除会失败。
/** * 删除一个Cookie * @param {string} name - 要删除的Cookie名称 * @param {Object} [options] - 必须与设置时的path和domain一致 * @param {string} [options.path] - 路径,默认'/' * @param {string} [options.domain] - 域名 */ function deleteCookie(name, options = {}) { // 关键:通过设置一个过去的过期时间来“删除” // 同时必须保持path和domain一致 setCookie(name, '', { ...options, // 继承传入的path和domain expiresDate: 'Thu, 01 Jan 1970 00:00:00 GMT' // 一个标准的过去时间 }); } // 使用示例:用户退出登录时 deleteCookie('user_token', { path: '/', secure: true }); // 注意:如果当初设置时指定了domain,这里也必须传入相同的domain3.5 进阶操作:获取所有Cookie与检查功能
有时我们需要查看或操作所有Cookie。
/** * 获取当前所有Cookie,并以对象形式返回 * @returns {Object} 所有Cookie的键值对对象 */ function getAllCookies() { const allCookies = document.cookie; const cookieObj = {}; if (!allCookies) { return cookieObj; } const cookiePairs = allCookies.split('; '); for (const pair of cookiePairs) { const [name, value] = pair.split('='); // 解码后存入对象 cookieObj[decodeCookieValue(name)] = decodeCookieValue(value); } return cookieObj; } /** * 检查某个Cookie是否存在 * @param {string} name - Cookie名称 * @returns {boolean} */ function hasCookie(name) { return getCookie(name) !== null; } // 使用示例 const allCookies = getAllCookies(); console.log('当前所有Cookie:', allCookies); console.log('是否有theme Cookie?', hasCookie('theme'));4. 第三方库js-cookie的深度使用与源码浅析
虽然自己封装能学到更多,但在生产环境中,使用一个成熟、稳定、经过充分测试的库是更明智的选择。js-cookie是目前最流行的Cookie操作库,它API简洁,兼容性好,且支持AMD/CommonJS模块化。
4.1 安装与基础API
你可以通过npm安装:npm install js-cookie,或者直接使用CDN。
<script src="https://cdn.jsdelivr.net/npm/js-cookie@3/dist/js.cookie.min.js"></script>它的基础API极其简单:
// 设置Cookie Cookies.set('name', 'value', { expires: 7, path: '/', secure: true, sameSite: 'lax' }); // 读取Cookie const value = Cookies.get('name'); // 返回 "value" const all = Cookies.get(); // 返回所有Cookie的对象 {name: 'value', ...} // 删除Cookie Cookies.remove('name', { path: '/', secure: true });你会发现,Cookies.remove同样需要正确的path和domain。
4.2 高级特性与配置
js-cookie提供了一些非常实用的高级特性:
1. 自动JSON转换: 这是我最喜欢的功能之一。你可以直接存储对象或数组,库会自动帮你序列化和反序列化。
const userPrefs = { theme: 'dark', language: 'zh-CN', fontSize: 14 }; Cookies.set('preferences', userPrefs, { expires: 30 }); const savedPrefs = Cookies.get('preferences'); console.log(savedPrefs.theme); // 输出 'dark',自动解析回了对象其原理是在set时内部调用JSON.stringify,在get时尝试JSON.parse,如果失败则返回原始字符串。
2. 默认属性配置: 你可以通过Cookies.defaults为后续所有操作设置默认属性,这在统一管理站点Cookie策略时非常有用。
// 假设你的站点全站HTTPS,且希望Cookie默认7天过期,路径为根目录 Cookies.defaults = { expires: 7, path: '/', secure: true, sameSite: 'lax' }; // 之后设置Cookie就简洁多了 Cookies.set('session_key', 'abc123'); // 自动应用上述默认属性3. 命名空间(Converter): 这是一个进阶功能,允许你为特定Cookie定义自定义的读写转换逻辑。例如,你希望所有日期类型的值都自动转换为Date对象。
// 定义一个针对`lastVisit`这个Cookie的转换器 Cookies.withConverter({ read: function(value, name) { if (name === 'lastVisit') { return new Date(value); // 将存储的字符串转换为Date对象 } return value; // 其他Cookie正常返回 }, write: function(value, name) { if (value instanceof Date && name === 'lastVisit') { return value.toISOString(); // 将Date对象转换为ISO字符串存储 } return value; } }); // 使用 Cookies.set('lastVisit', new Date()); const lastVisitDate = Cookies.get('lastVisit'); // 这里得到的是一个Date对象 console.log(lastVisitDate.getFullYear());4.3 源码核心逻辑借鉴
阅读js-cookie的源码(简化版)能加深理解。其set和get的核心逻辑与我们自己封装的思路一致,但更加健壮,处理了更多边界情况。
// 简化的 set 逻辑 function set (name, value, attributes) { // 1. 处理编码(它使用了一个更安全的编码函数) name = encode(name); value = encode(converter.write ? converter.write(value, name) : value); // 2. 构建属性字符串 var str = name + '=' + value; var expires = attributes.expires; if (typeof expires === 'number') { // 将天数转换为Date对象 expires = new Date(); expires.setMilliseconds(expires.getMilliseconds() + expires * 864e+5); } if (expires) { str += '; expires=' + expires.toUTCString(); } // ... 处理path, domain, secure, sameSite // 3. 赋值 document.cookie = str; } // 简化的 get 逻辑 function get (name) { var cookies = document.cookie ? document.cookie.split('; ') : []; for (var i = 0; i < cookies.length; i++) { var parts = cookies[i].split('='); var foundName = decode(parts.shift()); // 解码名称 if (name === undefined || name === foundName) { var cookieValue = parts.join('='); // 处理值中可能包含的'=' var result = decode(cookieValue); // 尝试JSON解析 if (result.substring(0, 2) === '{"') { try { result = JSON.parse(result); } catch (e) {} } // 应用转换器 return converter.read ? converter.read(result, foundName) : result; } } return null; }从源码可以看到,它在值解码后,会尝试判断字符串是否以{"开头,如果是则尝试JSON.parse,这实现了自动JSON转换。同时,它用parts.join('=')来处理Cookie值本身包含等号=的边缘情况,比简单的split('=')[1]更健壮。
5. 实战场景与避坑指南
理论说再多,不如看几个真实场景。下面是我在实际项目中遇到的典型用例和对应的坑。
5.1 场景一:用户登录态管理
这是Cookie最经典的用途。服务器在验证用户名密码后,生成一个加密的Session ID或JWT Token,通过Set-Cookie头种到浏览器。
// 假设登录API返回了token和用户信息 async function handleLogin(username, password) { try { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await response.json(); if (data.success) { // 通常服务器会通过Set-Cookie头自动设置,但有时前端也需要手动设置 // 例如,将服务器返回的token存储到Cookie Cookies.set('auth_token', data.token, { expires: 7, // 7天有效期 path: '/', secure: true, // 生产环境必须 sameSite: 'lax' }); // 同时可以将用户基本信息(如用户名)也存入Cookie,避免频繁请求 Cookies.set('user_info', JSON.stringify({ name: data.userName, role: data.role }), { expires: 1 }); console.log('登录成功,Cookie已设置'); window.location.href = '/dashboard'; } } catch (error) { console.error('登录失败:', error); } }避坑点:
- Token安全:认证Token(如JWT)本身可能包含敏感信息。确保服务器对Token进行了签名(如使用HMAC或RSA),并且前端无法篡改。
secure和httpOnly(此属性只能由服务器设置,JavaScript无法读取)是保护Token的关键。 - HttpOnly Cookie:对于最核心的会话标识,强烈建议服务器将其设置为
HttpOnly。这样,即使网站存在XSS漏洞,恶意脚本也无法通过document.cookie窃取该Cookie,极大增强了安全性。此时,前端JavaScript不需要、也无法操作这个Cookie,它仅由浏览器自动在请求中携带。
5.2 场景二:跨子域共享登录状态
公司有www.example.com(主站)和admin.example.com(后台)两个子域,希望用户在一个站点登录后,访问另一个站点时也保持登录状态。
解决方案:在设置认证Cookie时,指定domain为.example.com(注意前面的点)。
// 在 www.example.com 登录成功后 Cookies.set('shared_session', 'session_id_abc', { expires: 1, path: '/', domain: '.example.com', // 关键!允许所有子域访问 secure: true, sameSite: 'lax' });这样,用户在访问admin.example.com时,浏览器也会自动带上这个Cookie。
避坑点:
- 域名匹配规则:
domain设置为.example.com可以匹配example.com本身及其所有子域(如www.example.com、admin.example.com)。但不能匹配父域或其他不相关域名。 - 端口和协议无关:Cookie的域匹配不关心端口号(
localhost:8080和localhost:3000被视为不同源,但Cookie域规则不涉及端口)和协议(HTTP/HTTPS),但secure属性会限制协议。
5.3 场景三:简单的用户偏好设置
对于一些非敏感的用户设置,如主题色、语言偏好,使用Cookie存储是个简单直接的选择。
// 保存主题偏好 function saveThemePreference(theme) { Cookies.set('user_theme', theme, { expires: 365 }); // 保存一年 applyTheme(theme); // 立即应用主题 } // 页面加载时读取并应用 function initPage() { const savedTheme = Cookies.get('user_theme') || 'light'; // 默认亮色主题 applyTheme(savedTheme); // 绑定主题切换按钮事件 document.getElementById('themeToggle').addEventListener('click', () => { const newTheme = savedTheme === 'light' ? 'dark' : 'light'; saveThemePreference(newTheme); }); }避坑点:
- 存储容量限制:每个Cookie通常最大为4KB,且每个域名下的Cookie总数和总大小也有限制(通常为50个左右,总大小4KB左右)。对于复杂的配置,考虑使用
localStorage(容量约5MB)。 - 性能影响:由于Cookie会在每一个同域请求的HTTP头中被自动发送,如果存储了大量数据,会无形中增加请求的负载,影响性能。因此,只将真正需要服务器知晓的数据放在Cookie里。
5.4 场景四:与LocalStorage的抉择
这是一个常见问题:我该用Cookie还是LocalStorage?
| 特性 | Cookie | LocalStorage |
|---|---|---|
| 生命周期 | 可设置过期时间,或为会话级 | 持久存储,除非手动清除 |
| 存储容量 | 约4KB(每个) | 约5MB(每个域名) |
| 数据位置 | 浏览器和服务器(通过HTTP头) | 仅浏览器 |
| 自动发送 | 是(每次请求自动携带) | 否 |
| 可访问性 | 可通过document.cookie(非HttpOnly)和HTTP头访问 | 仅通过JavaScript API访问 |
| 主要用途 | 会话管理、身份认证、需要服务器知晓的简单数据 | 纯前端缓存、大量用户偏好设置、离线数据 |
选择建议:
- 选Cookie:数据需要被自动发送到服务器,用于维持状态(如登录Session、购物车ID)。或者数据很小,且需要设置精确的过期时间。
- 选LocalStorage:数据纯粹供前端使用,不需要发给服务器,且数据量可能较大(如用户编辑器的草稿、缓存的API响应数据)。
一个常见的混合模式是:用HttpOnly的Cookie存储核心会话ID保证安全,同时用LocalStorage存储用户界面相关的偏好(如主题、列表排序方式),两者互补。
6. 常见问题排查与调试技巧
即使理解了所有原理,在实际开发中还是会遇到各种“诡异”的问题。下面是我总结的排查清单。
6.1 问题一:Cookie设置成功了,但读取不到/请求中未携带
这是最高频的问题。请按以下顺序排查:
- 检查路径(Path):你是否在
/admin路径下设置的Cookie,然后试图在首页/读取它?Cookie的路径必须匹配。最稳妥的方式是始终设置path='/'。 - 检查域名(Domain):你是否在
www.example.com设置,但试图在app.example.com读取?需要设置domain='.example.com'来实现跨子域共享。 - 检查Secure属性:如果你的网站是HTTPS,但Cookie设置了
secure=true,那么当你在本地开发环境(HTTP)测试时,这个Cookie是无效的,既无法设置也无法读取。本地开发时请暂时注释掉secure选项。 - 检查SameSite属性:这是现代浏览器(Chrome 80+, Firefox 79+等)的默认行为变化导致的经典问题。
- 现象:用户从第三方网站(如邮件链接)点击进入你的网站,发现是未登录状态。
- 原因:现代浏览器默认将未指定
SameSite的Cookie视为Lax。Lax模式下,从外部链接发起的跨站请求(即使是GET请求)在某些严格实现下也可能不携带Cookie。 - 解决方案:如果你的应用依赖跨站请求携带Cookie(例如单点登录SSO场景),必须显式设置
sameSite='none'; secure=true。并且必须使用HTTPS。
- 检查浏览器设置:用户可能禁用了第三方Cookie,或者使用了隐私浏览模式。可以在浏览器开发者工具的Application(或Storage)标签页中,直接查看当前页面下所有可用的Cookie,这是最直接的调试手段。
6.2 问题二:Cookie值包含特殊字符导致被截断
如果你尝试存储一个包含分号的字符串,比如"user;admin",它会破坏Cookie的格式。
// 错误示例 document.cookie = "role=user;admin"; // 浏览器会理解为:name=role, value=user; 然后admin成了一个独立的无效片段 console.log(document.cookie); // 可能只输出 "role=user"解决方案:始终对值进行编码。
// 正确示例(使用我们的封装函数或js-cookie) setCookie('role', 'user;admin', { expires: 7 }); // 或 Cookies.set('role', 'user;admin', { expires: 7 }); // 实际存储的是 "role=user%3Badmin",读取时会自动解码回 "user;admin"6.3 问题三:删除Cookie失败
删除的本质是设置过期,如果path或domain不匹配,就会创建一个新的、无效的Cookie,而旧的依然存在。
// 假设当初这样设置 Cookies.set('myCookie', 'value', { path: '/dashboard', secure: true }); // 这样删除会失败,因为path不匹配 Cookies.remove('myCookie'); // 默认path是'/' // 这会在根路径'/'下创建一个名为myCookie的过期Cookie,但原路径'/dashboard'下的还在 // 正确删除方式 Cookies.remove('myCookie', { path: '/dashboard', secure: true });黄金法则:删除Cookie时,传入的path、domain、secure属性必须与设置时完全一致。养成在设置Cookie后,将配置保存下来的习惯(例如存到一个常量对象里),删除时直接引用。
6.4 开发者工具实战调试
现代浏览器的开发者工具是调试Cookie的利器(以Chrome为例):
- 查看所有Cookie:打开开发者工具 (F12) -> Application (或 Storage) -> Cookies。这里会按域名列出所有Cookie,并清晰展示其
Name、Value、Domain、Path、Expires/Max-Age、Size、HttpOnly、Secure、SameSite属性。一目了然。 - 实时监控Cookie变化:在开发者工具 -> Network标签页,点击任意一个网络请求,在Headers选项卡中查看Request Headers里的
Cookie字段,以及Response Headers里的Set-Cookie字段。这是观察Cookie在客户端和服务器间如何传递的最直接方式。 - 手动编辑与删除:在Application -> Cookies面板,你可以直接双击某个Cookie的值或属性进行编辑,也可以右键删除。这在测试不同场景时非常方便。
掌握这些调试技巧,能让你在遇到Cookie相关问题时,快速定位是前端设置问题、浏览器策略问题还是服务器配置问题。