为什么本地文件用 fetch 请求 JSON 会报 CORS 错误?
我最近在本地开发一个静态页面,想用 fetch('data.json') 加载同目录下的 JSON 文件,结果浏览器控制台报错:「Access to fetch at ‘file:///…/data.json’ from origin ‘null’ has been blocked by CORS policy」。明明是本地文件,又没跨域,怎么会触发 CORS?
我已经试过把文件放到 VS Code 的 Live Server 里跑,这样就能正常加载,但直接双击 HTML 文件打开就不行。是不是因为 file:// 协议的问题?有没有办法在不启动服务器的情况下解决?
file://协议搞的鬼。问题的根源在于浏览器的安全策略。当你直接双击 HTML 文件打开时,地址栏是
file:///开头的,这时候页面的 origin 被浏览器定义为字符串"null"。注意不是空字符串,而是字符串 "null"。当你用 fetch 请求另一个本地文件时,浏览器会认为这是从一个 origin 为 "null" 的源去访问另一个源,即使它们在同一个文件夹里。Chrome 和其他现代浏览器出于安全考虑,禁止
file://协议的页面发起任何 AJAX 或 fetch 请求。这个设计是为了防止恶意网页读取你本地的文件系统,想象一下如果网页能随意读取你电脑上的文件,那得多危险。Live Server 能跑通是因为它启动了一个本地 HTTP 服务器,你的页面变成了
http://127.0.0.1:5500,请求 JSON 文件时是同源的,自然就没有 CORS 问题了。如果你非要不用服务器,有几种方案,但都有局限。
方案一,给 Chrome 加启动参数。关闭所有 Chrome 窗口,然后用命令行启动:
这个方法能跑,但我不建议用。首先每次都要手动启动很麻烦,其次这会关闭浏览器的安全策略,你日常上网千万别用这个模式的浏览器。
方案二,把 JSON 数据直接内嵌到 JS 文件里。如果你的数据是静态的,不经常变动,直接写成一个变量:
然后在 HTML 里用
引入,直接用localData这个变量就行。简单粗暴,但失去了 JSON 文件的灵活性。方案三,如果你只是想快速测试,可以用 Python 一行命令起个服务器。前提是你电脑装了 Python:
或者用 Node.js 的
http-server包,全局安装后直接运行就行。说到底,本地开发起个服务器是正道。VS Code 的 Live Server 插件也好,Python 的简易服务器也好,都是几秒钟的事。浏览器的安全策略不是来跟你作对的,是真的在保护用户。我之前为了调试一个本地存储的问题折腾了半天,最后发现就是
file://协议下 localStorage 的行为和http://也不一样,坑多了去了。总结一下,没有服务器的情况下完美解决这个问题的方案基本没有,要么接受安全风险改浏览器参数,要么把数据内嵌,要么老老实实起个本地服务器。建议还是用 Live Server 或者其他本地服务器方案,省心。