origin
There is a department in our company that needs to do micro front-end, and there is a JS link for both the main application and the sub-application, but whether the JS of the sub-application is found to be cross-domain during deployment. And there is no problem when the sub-application is started alone.
Since it is a cross-domain problem, go to OSS to see if cross-domain is set. It is found that cross-domain has been set up.
At this time, the careful friends have found the problem and thought of a solution
decrypt
There are three reasons for this problem:
- Micro frontend loading sub-application process
- Cloud vendor strategy
- Browser Caching Policy
Micro front terminal application process
Careful friends will find that the JS of the main application type
is script
, but the JS of the sub- type
application is of fetch
type , which involves the process of loading sub-applications in the micro-frontend.
The entrance of the micro-frontend is an html address. In order to achieve JS sandbox and CSS isolation, the basic process is:
- First get the HTML text content
- Analyze HTML text content and get an array of JS and CSS links for external links
- Iterate over the array to
fetch
get each JS and CSS text via - Execute JS text through eval function, and implement sandbox through proxy window object; CSS increases isolation by adding prefix
Let's take qiankun as an example to see the process of obtaining JS links:
Source: github.com/kuitos/impo…
So the sub-app's type
is fetch
not normal script
.
But if you think that it is fetch
only cross-domain, but fetch
there is no problem with it alone.
Cloud vendor strategy
我测试了两家国内知名云厂商,发现都是如下策略:对于非跨域请求,则不返回跨域头,对于跨域请求才返回跨域头。 当然其目的当然是好的,因为跨域的情况下,在未设置 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. The main application script adds crossorigin
attributes
Since the fetch
request reuses the first response result, it would be fine if it returns the result with the cross-domain header for the first time, so we can let the script return the cross-domain header information through the crossorigin header.
4. Increasevary: origin
We saw that in Alibaba Cloud's cross-domain settings, there is a selection box that allows you to choose whether to add vary: origin
this header.
Vary is an HTTP response header that determines whether a cached response should be used or a new response should be requested from the origin server for a future request header. It is used by the server to indicate which headers should be used when selecting a resource representative in the content negotiation algorithm.
So why Vary: origin
is it possible to distinguish between fetch
request script
and ?
It turns out that there script
is no origin
such request header, and the fetch method is forced to be added by the browser because it is cross-domain Origin
. Because of the vary: origin
response header, it leads to fetch and can reuse script
the response of the request, so it also avoids cross-domain.
concluding remarks
Although the problem is small, it still brings out a lot of knowledge. Have you learned it?