“Cookie 已经清了,为什么登录状态还在?”在多账号环境排查里,这个问题比想象中常见。多数人把浏览器存储等同于 Cookie,但现代 Web 应用还会把会话、缓存和离线数据写进 localStorage、IndexedDB、CacheStorage 和 Service Worker。只清 Cookie,相当于只擦了门口的一块地。
浏览器里的持久化存储至少有五类:
这些存储的清除方式不同。浏览器设置里的“清除 Cookie 和网站数据”通常会覆盖它们,但脚本里如果只操作 document.cookie,往往只覆盖了 Cookie 这一层。很多“清了还是登录”的问题,根源就在这里。
过去,第三方 iframe 里的存储主要按自身 origin 划分。一个嵌在多个网站里的客服、支付或登录组件,可能在不同顶层站点之间共享同一份存储,从而识别出同一个用户。
存储分区(Storage Partitioning)改变了这个规则:第三方上下文中的存储不再只按 origin 划分,还要加上顶层站点的分区键。也就是说,同一个 iframe 域名,嵌在 A 站和 B 站里,可能对应两套独立的 Cookie、localStorage 和 IndexedDB。第三方 Cookie 的限制更严格时,未声明 Partitioned 的 Cookie 可能根本不会被写入。
这对隐私是好事,对多账号运营却提出了新要求:你不能假设“同一个域名下的存储一定共享”,也不能假设“清掉顶层站点的 Cookie,第三方组件的数据就没了”。分区键、浏览器版本、站点对 Storage Access API 的使用,都会改变最终结果。
Storage Access API 提供了一条受控通道:嵌入方可以调用 document.hasStorageAccess() 检查权限,再用 document.requestStorageAccess() 申请访问。它解决的是“用户已授权场景下如何跨分区读取”,不是绕过分区。把这个 API 当成万能钥匙,同样会踩坑。
第一种是登录 token 残留。 很多单页应用把 access token 放在 localStorage,刷新页面时直接读取。只清 Cookie,token 还在,页面自然还是登录态。
第二种是 IndexedDB 里的业务数据。 订单缓存、草稿、联系人、图片 Blob 都可能存在 IndexedDB。换账号后如果没清,轻则看到上一个账号的残留数据,重则把旧数据写进新账号。
第三种是 Service Worker 的缓存。 Service Worker 注册在 origin 上,能拦截请求并返回缓存响应。即使 Cookie 清了,旧的 API 响应仍可能从 CacheStorage 里被读出来,表现为“退了登录但页面还是旧数据”。
这三种残留,靠“退出登录”按钮不一定能清干净。退出登录通常只清会话 Cookie 或服务端 token,不一定删除本地缓存。环境隔离要认真做,就得把存储当成一个整体来审计。
在目标站点的控制台里,可以先做只读检查:
// 仅用于自有环境的排查,在目标站点控制台执行
console.log('localStorage:', Object.keys(localStorage));
console.log('sessionStorage:', Object.keys(sessionStorage));
console.log('IndexedDB:', await indexedDB.databases());
console.log('CacheStorage:', await caches.keys());
const regs = await navigator.serviceWorker.getRegistrations();
console.log('Service Workers:', regs.map((r) => r.scope));indexedDB.databases() 目前在 Chromium 内核浏览器中可用,其他内核的支持情况不一致,读不到时可以用 DevTools 的 Application 面板代替。
需要清理时,按下面的顺序更稳妥:
// 如果页面仍持有数据库连接,删除可能被 blocked;先关闭连接或刷新页面
await Promise.all((await caches.keys()).map((k) => caches.delete(k)));
for (const db of await indexedDB.databases()) {
if (db.name) indexedDB.deleteDatabase(db.name);
}
localStorage.clear();
sessionStorage.clear();更彻底的做法是使用浏览器的“清除站点数据”,或者在 DevTools 的 Application → Storage 里勾选全部存储类型。清理后刷新页面,再检查 Service Worker 是否重新注册、IndexedDB 是否被重建。
清理是补救,隔离才是日常。多账号场景下,更可靠的做法是每个账号使用独立的浏览器 profile:Cookie、localStorage、IndexedDB、CacheStorage 和 Service Worker 都落在各自的用户数据目录里,切换账号时整体切换,而不是在同一个 profile 里反复清数据。
独立 profile 仍然共享 IP、时区、字体和硬件指纹,所以它解决的是存储隔离,不是完整的设备隔离。要覆盖身份层,还需要代理、时区和指纹模板一起配置。
另外,不要把无痕窗口当成独立环境。无痕模式会隔离部分存储,但关闭窗口后数据消失,不适合需要保持登录的长期运营;它也不改变 IP 和硬件指纹。
浏览器存储隔离不是“清 Cookie”四个字。Cookie、localStorage、IndexedDB、CacheStorage、Service Worker 各有各的生命周期,存储分区又给第三方上下文加了一层键。排查时先枚举,再清理,最后用独立 profile 把隔离固化下来。
对多账号团队来说,最危险的不是不知道这些存储类型,而是假设“退出登录就等于清干净了”。把假设换成检查清单,很多反复登录、数据串号的问题会更容易定位。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。