DEV Community

为什么本地打开的HTML用不了OPFS,却能用IndexedDB?

双击本地 HTML 文件(file:// 协议)运行时,常会遇到一个反直觉的现象:OPFS(源私有文件系统)直接报错不可用,但 IndexedDB 却能正常读写存储。这并非代码 bug,而是浏览器安全模型与 API 设计共同决定的结果。

OPFS 不可用的核心原因:两个硬性门槛全不满足

OPFS 是 File System Access API 的子集,全称为 Origin Private File System。它的设计从底层就绑定了“源(Origin)”与“安全上下文”两个概念,而 file:// 协议恰好两者都不满足。

强制要求安全上下文

OPFS 属于高权限的文件系统类 API,W3C 标准与主流浏览器实现均要求其必须在安全上下文(Secure Context)中运行,仅认可 https://http://localhost 两类环境。

file:// 协议下调用 navigator.storage.getDirectory() 时,浏览器会直接抛出 SecurityErrorNotSupportedError--尽管部分标准文档将 file:// 归为“潜在可信”,但 Chromium 等内核针对文件系统 API 做了更严格的安全收紧,直接禁用了本地文件场景的 OPFS 能力。

没有明确的“源”,就没有隔离的私有空间

OPFS 的核心设计是按源隔离:每个网站(协议+域名+端口)拥有一个独立、用户不可见的私有文件目录,跨源完全无法互相访问。

file:// 协议没有主机名、端口的概念,浏览器会将其源标记为 null(不透明源)。面对一个“没有身份”的页面,浏览器无法为它分配独立的 OPFS 存储分区,也无法保障文件系统的安全隔离边界,因此直接禁用了该能力。

IndexedDB 为何能在本地文件中正常工作?

IndexedDB 同样遵循同源策略,却能在 file:// 场景下正常使用,本质是历史兼容性与存储模型的差异

更早的标准,更宽松的兼容实现

IndexedDB 是 HTML5 时代就定型的老牌存储 API,出现时间远早于 OPFS。主流浏览器在实现阶段就对本地文件场景做了兼容处理:虽然 file:// 的源为 null,但浏览器会基于文件的本地路径来做存储分区--同目录下的 HTML 文件共享同一份 IndexedDB 数据,不同目录互相隔离,变相实现了存储隔离的安全要求。

存储模型更适配无源头场景

IndexedDB 是数据库型存储,数据由浏览器内部的数据库引擎(如 LevelDB)统一管理,只需要一个“分区标识”就能完成隔离;而 OPFS 是文件系统级抽象,需要严格的源身份来映射磁盘上的私有目录,对源的合法性要求更高。

因此 IndexedDB 可以通过“路径映射源”的方式兼容 file://,而 OPFS 从设计上就不支持这种模糊的身份标识。

解决方案

如果需要在本地使用 OPFS,不要直接双击 HTML 文件,请通过本地静态服务启动(如 python -m http.server、Vite 等),以 http://localhost:端口 的形式访问页面--此时既有明确的源,也满足安全上下文要求,OPFS 即可正常工作。

Comments

No comments yet. Start the discussion.