
问题复现:学习 ES6 模块化的时候,写了这段代码:javascript
<script src="./aaa.js" type="module"></script>
<script src="./bbb.js" type="module"></script>
<script src="./aaa2.js" type="module"></script>
结果跑到 chrome 下面一看,报错了:html

看起来是跨域问题,也就是只支持 http
,https
等这种类型的跨域请求,不支持 file
协议类型的(直接本地打开文件)。解决方案以下:前端
1.给 chrome 快捷方式添加参数:–allow-file-access-from-files
实测无效。貌似还得重启电脑,太麻烦了,遂放弃。java
2.换浏览器。通过测试,Edge 能够正常显示,但 FireFox 仍是报跨域错误:web

3.用 IDE。像 Webstrom 这类型的 IDE 是内置 http 服务器的,这样能够不经过 file
协议打开文件,不过这个仍是有点麻烦,我没尝试。chrome
4.使用热更新插件。恰好想起编辑器里安装了 live server 这个插件,这个实际上是作同步刷新用的,可是因为它能够在本地开启一个服务器,因此能够利用这一点(localhost 访问)。尝试以后发现确实不报错了。express
5.Node 开一个服务器跨域
// server.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.get('/',function (req,res) {
res.send('./index.html',{root:__dirname});
})
app.listen(8203);
问题是解决了,但总以为内心不踏实,因此开始了艰苦的 google 之旅,最后算是找到了问题的根源。但我仍是想从同源策略开始解释:浏览器
“同源策略(Same origin policy),是出于安全而诞生的一种约定,规定了只能在本域内进行资源访问。所谓同源是指"协议+域名+端口"三者相同。安全
不一样源之间进行资源访问,就须要跨域。特殊地,有三个标签默认是容许跨域加载资源的:
-
<img src="xxx">
-
<link href="xxx">
-
<script src="xxx">
关键来了,ES6 使用模块的时候要在标签中声明 type="module"
,而这类使用了模块的 script
是受限于同源策略的。咱们尝试改动以前的代码以下:
<script src="./aaa.js" type="module" defer="defer"></script>
<script src="./bbb.js" type="module" defer="defer"></script>
<script src="./ccc.js" type="text/javascript" defer="defer"></script>

能够看到,前面两个 script
使用了模块,Sec-Fetch-Mode
都是 cors
,而最后一个就是常规的引入脚本,不受同源策略影响,所以是 no-cors
。
咱们能够理解为前两个 scirpt
发送了 Cors 跨域资源请求,而这种请求要求 request header 的 origin 必须合法 —— 也就是必须带有 http
,https
等,以用来代表请求源。
可是别忘了,咱们如今是在本地打开文件,使用的不是 http
协议,而是 file
协议,它根本就没有跨域请求须要的 origin
(注意看上图,origin
是空的)。因此,这种状况就要报错了。其实从报错信息中也能读出这一点。
那么,咱们如今用 live server 在本地开启服务器,再看一下控制台:

能够看到,由于此次不是用 file
协议访问了,因此一切正常。
参考:
Understanding ES6
ModulesES6 module support in Chrome 62/Chrome Canary 64, does not work locally, CORS error
Access to Image from origin 'null' has been blocked by CORS policy
本文分享自微信公众号 - 漫游前端世界(gh_6ac344b74a01)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。