浏览器存储配额与持久化机制 (Browser Storage Quota & Persistence):现代浏览器为同源(Same-Origin)提供的客户端离线持久化存储规范(IndexedDB, Cache API, Origin Private File System / OPFS)及其配额管理与防驱逐策略。


核心概念:存储容量与模型上下文解耦

在构建端侧/浏览器内 AI Agent(如端侧 Web 智能体、虚拟文件系统 VFS)时,极易产生一种认知混淆:将大模型的输入上下文窗口(Context Window Token Limit)误当作客户端的存储上限。

  • 浏览器存储(Browser Storage):承载静态资产、用户工作区工程文件、文档与音视频。由客户端本地磁盘决定,容量量级在 100MB 至 100GB 之间。
  • 模型上下文(Model Context Window):承载 Agent 单次交互时的 Prompt 与 Tool 响应内容。受限于模型注意力机制和 Token 预算(例如 128k ~ 1M tokens)。
  • 解耦原则:

    • 存储层放开:IndexedDB 存储限额应当贴合用户本地项目需求(如 128MB ~ 数 GB),单文件放宽至数十 MB。
    • 工具层防御(Context Guard):在 Agent 读文件工具(read_file)中实施守卫,防止读取整个庞大二进制(如 PDF/图片)或巨型文本,仅向模型返回结构化元数据(文件类型、尺寸、大纲)或行切片(Line-slice Truncation),从而既保证浏览器装得下全部资产,又确保模型上下文不被击穿。

浏览器真实配额与驱逐策略 (Quota & Eviction)

浏览器内核 / 平台单站 IndexedDB / Cache 上限驱逐机制 (Eviction Policy)持久化权限影响
Chromium / Blink (Chrome, Edge)本地可用磁盘空间的 60%(通常可达数十 GB 至上百 GB)临时存储模式下,当磁盘空间不足(全局超过 80%)按 LRU 自动清理获得 persistent 授权后免遭自动驱逐
Gecko (Firefox)默认约为 2GB 或磁盘空闲的 10%~50%(可按需向用户弹窗申请扩容)磁盘紧张时按 LRU 清理非持久化站点获得 persistent 授权后常驻
WebKit (Safari / iOS)默认单站约 1GB 左右7 天未使用自动删除(ITP 智能防跟踪与清理策略)persist() 成功后可豁免 7 天清理

关键 Web API

现代标准统一通过 navigator.storage(StorageManager API)进行容量探测与生命周期提升:

1. 动态配额与使用量查询 (estimate)

export interface BrowserStorageEstimate {
  quotaBytes: number;
  usageBytes: number;
  isPersisted: boolean;
}

export async function checkStorage(): Promise<BrowserStorageEstimate> {
  if (typeof navigator === 'undefined' || !navigator.storage?.estimate) {
    return { quotaBytes: 0, usageBytes: 0, isPersisted: false };
  }

  const [estimate, isPersisted] = await Promise.all([
    navigator.storage.estimate(),
    navigator.storage.persisted ? navigator.storage.persisted() : Promise.resolve(false),
  ]);

  return {
    quotaBytes: estimate.quota ?? 0,
    usageBytes: estimate.usage ?? 0,
    isPersisted: Boolean(isPersisted),
  };
}

2. 持久化存储模式申请 (persist)

浏览器存储默认是 Best-effort(尽力型)。调用 persist() 可以申请切换为 Persistent(持久型):

export async function requestPersistentMode(): Promise<boolean> {
  if (typeof navigator === 'undefined' || !navigator.storage?.persist) {
    return false;
  }
  // 某些浏览器(Chrome)基于书签、PWA安装状态、通知授权或访问频次自动放行
  // Firefox 通常会向用户弹出权限确认框
  return await navigator.storage.persist();
}

大文件与二进制资源的高保真渲染方案

在浏览器虚拟文件系统中支持 PDF 等富媒体文件时,有两条渲染路线:

  1. Data URL 模式(反模式):

    • 将 Base64 编码直接拼入 <iframe src="data:application/pdf;base64,...">。
    • 缺点:大文件(数 MB 以上)会引起页面内存膨胀约 33%,且主流浏览器对导航至高长度 Data URL 存在安全阻断或白屏现象。
  2. Blob URL 模式(推荐模式):

    • 将 Base64 解码为二进制 Uint8Array,封装为 new Blob([buffer], { type: 'application/pdf' })。
    • 使用 URL.createObjectURL(blob) 生成同源引用链接,挂载至原生 iframe 或 <embed>。
    • 利用浏览器原生内置的 PDF 查看器(带缩放、目录树、高保真矢量渲染、页码跳转与打印功能),并在组件卸载时及时调用 URL.revokeObjectURL(url) 释放内存。

常见坑与排查经验 (Pitfalls)

  1. 隐身 / 无痕浏览模式 (Incognito / Private Mode):

    • 隐身模式下 navigator.storage.persist() 会直接返回 false。
    • 配额会被大幅度压缩(例如限制在 100MB 或内存临时映射),关闭窗口即全部销毁。
  2. Safari 7 天清理陷阱:

    • 若未获得 Persistent 权限,用户超过 7 天未打开该 PWA/网页,Safari 会将整个 Origin 的 IndexedDB 与 LocalStorage 清空。对于重度依赖本地存储的 Web 应用,首屏应当引导用户申请持久化或添加至主屏幕。
  3. Agent 工具上下文击穿:

    • 若未对 read_file 增加二进制拦截,Agent 会试图把几十万字符的 Base64 塞进 Prompt,瞬间耗尽上下文 Token 配额导致调用失败。务必在 Tool 层面拦截所有非纯文本 MIME 类型。

相关概念


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web