起因
我们公司有一个部门需要做微前端,其中有一个 JS 链接主应用和子应用都需要,但是在部署的是否发现了子应用的 JS 出现了跨域的情况。

而且子应用单独启动时,是没有任何问题的。
既然是跨域问题,那赶紧去 OSS 看看有没有设置跨域。

发现已经设置了跨域呀。

此时细心的小伙伴已经发现了问题,并想到了解决方案
解密
造成这个问题的原因有三个:
- 微前端加载子应用过程
- 云厂商策略
- 浏览器缓存策略
微前端子应用过程

细心的小伙伴会发现,主应用的 JS 的 type 是 script,但是子应用的 JS 的 type 却是 fetch类型,这就涉及到微前端加载子应用的过程。
微前端的入口是一个 html 地址,其为了实现 JS 沙箱和 CSS 隔离,其基本流程是:
- 先获取 HTML 文本内容
- 分析 HTML 文本内容,获取外链的 JS 和 CSS 链接数组
- 遍历数组,通过 fetch获取每个 JS 和 CSS 文本
- 通过 eval 函数执行 JS 文本,并通过代理 window 对象,实现沙箱;CSS 通过增加前缀增加隔离
我们以 qiankun 为例,看一下其获取 JS 链接的过程:

所以子应用的 type才是 fetch 而不是正常的 script。
但如果你是觉得只是因为 fetch 才跨域的,但实际单独 fetch是没有任何问题滴。


云厂商策略
我测试了两家国内知名云厂商,发现都是如下策略:对于非跨域请求,则不返回跨域头,对于跨域请求才返回跨域头。


当然其目的当然是好的,因为跨域的情况下,在未设置 Access-Control-Max-Age或者其值过期的情况下,就算文件未改变的情况下,还是会导致发起请求,询问是否跨域,增加了请求量。
但是到这里我们还是不明白为什么两个同时请求时,就会 GG。

浏览器缓存策略

我们仔细观察报错的请求,发现 fetch 请求只有 Response Headers并没有 Request Headers,怎么回事呢?
原因也很简单,就是因为浏览器没有发起请求,此请求被认为其和上一个 JS 是同一个资源,所以返回了上一个请求的 Response。
真相大白

通过上述三点分析我们已经彻底明白了:
- 首先是微前端的主应用先通过 script请求到 JS,(云厂商 Response 里没有跨域头)
- 然后微前端框架通过 fetch方式获取子应用的 JS
- 然后浏览器发现这个资源加载过了,于是就返回了 script 的 Response,但是由于没有跨域头,所以浏览器就报了跨域错误。
解决方案
1、子应用区分开发和生产环境
由于是同一份 JS,其实子应用没有必要重新加载一遍的,我们可以通过类似 html-webpack-plugin区分开发环境和生产环境。
- 当子应用本地开发时,将 JS 添加到 HTML 模板中;
- 当生产构建环境时,不将其打进,如此就可以完美解决上述问题。
2、资源无缓存
我们知道了,本质上其由于浏览器缓存策略引起的,那我们就可以增加 cache-control: no-cache 的方式,不允许浏览器利用缓存,也可以完美解决这个问题。

坏处:会导致流量增加
3、主应用 script 增加 crossorigin 属性
由于fetch 请求复用了第一次的响应结果导致的报错,如果第一次就让他返回带跨域头的结果不就可以了嘛,所以我们可以通过 crossorigin 头,让 script 返回跨域头信息。

4、增加 vary: origin

我们看到阿里云跨域设置中,有一个选择框就是让你选择是否增加 vary: origin 这个 header 头。
Vary 是一个HTTP响应头部信息,它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。它被服务器用来表明在 content negotiation algorithm(内容协商算法)中选择一个资源代表的时候应该使用哪些头部信息(headers).
那为什么 Vary: origin可以区分 fetch 请求 和 script 呢?
原来 script 是没有 origin 这个请求头的,而 fetch 的方式因为跨域,所以浏览器会强制加上  Origin。


因为 vary: origin响应头的原因,所以导致 fetch 并能复用 script方式请求的 response,所以也避免了跨域。
结束语
虽然问题很小,但是引出来的知识还是挺多的,你学到了吗?
























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
