问题描述
今天尝试用ES6的module特性,引入文件时遇到了跨域问题:
//html
<script type="module" src="./index.js">
</script>
//index.js
import{cars} from './cars.js';
const message=cars[0].make;
document.getElementById('message-element')
.textContent=message;
//cars.js
//making a module
const carsJson=`[
{
"year": 2000,
"make": "Honda",
"model": "Accord",
"price": 2801
},
{
"make": "Nissan",
"model": "Leaf",
"year": 2020,
"price": 1801
},
{
"make": "Ford",
"model": "F150",
"year": 2020,
"price": 19501
},
{
"year": 2021,
"make": "fwef",
"model": "cool",
"price": 1200
}
]`
export const cars=JSON.parse(carsJson);
解决方案
在atom编辑器中安装了atom-live-server插件,用来在本地开一个服务器,避免了使用file协议,成功的解决了问题。
插件的安装参考了https://blog.csdn.net/Asuna_Yu/article/details/80358949
原因分析
同源策略
起初同源策略的含义是A网站设置的cookie,B网站不能打开,除非两个网站“同源”:协议相同、域名相同、端口相同。
现在,如果非同源,主要有三种行为会受到限制:
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
举一个具体的例子:你向登录购物网站A请求接口进行登录,然后A网站的服务器给你发送Set-Cookie,然后你接下来浏览网站A,再次发送请求时,浏览器就会自动将cookie附加在http请求的头字段Cookie中,服务器就知道你已经登陆过了。这时你被打断,打开了网站B(恶意网站),网站B读取了网站A的Cookie并向A的服务器发送请求,在你没有退出登录的情况下,网站B相当于登陆了你的账号。这种攻击叫做CSRF攻击。
同源策略是一件保护用户信息安全的好事,但是有时我们开发的正常操作也会受到影响,如何解决?
<script> <img> <link>这些标签默认是不受到同源策略的限制的,可以跨域请求,常规的请求的Sec-Fetch-Mode域是no-cors。而ES6使用模块Module需要在script标签中指定type="module",这类使用了module的标签是受限于同源策略的,这类请求的Sec-Fetch-Mode域是cors,cors请求的request header的origin必须合法,即必须包含上面报错图中的http,data,chrome,https等协议的信息,file协议是不行的,甚至没有request header的信息。因此,在本地开启http服务器,所以正常了。
ES6标准中对于module有如下描述:
Regular <script>
tags can fetch scripts on other domains but modules are fetched using cross-origin resource sharing (CORS). Modules on different domains must therefore set an appropriate HTTP header, such as Access-Control-Allow-Origin: *
.
Finally, modules won’t send cookies or other header credentials unless a crossorigin="use-credentials"
attribute is added to the <script>
tag and the response contains the header Access-Control-Allow-Credentials: true
.
也就是说module是需要通过跨域请求访问的资源,不同源的服务端需要设置Access-Control-Allow-Origin字段才可以访问。然后,为了安全,除非在<script>标记中添加了一个crossorigin =“ use-credentials”属性,并且响应包含标头Access-Control-Allow-Credentials:true,否则modules将不会发送cookie或其他标头凭证。
参考文献:
https://www.sitepoint.com/understanding-es6-modules/
https://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html