当我们谈论前端跨域时,我们到底在说什么?
在使用上来说,iframe 跨域是比较麻烦的一种(创建新元素 -> 处理跨域交互),但是伟大的邓小平同志说过:
不管是黑猫还是白猫,只要能抓住老鼠,就是好猫。
所以,作为一种经典的跨域方式,还是要把它单独提溜出来念叨念叨。 根据使用场景和方式的不同,iframe 跨域分为以下几种:
适用场景:不同子域,相同主域 举个栗子,有两个 url,分别是:https://kyrieliu.cn/a.html 和 http://www.kyrieliu.cn/b.html(主域是相同的)。 这个时候,b 页面通过 iframe 内嵌在 a 页面中,iframe 的 onload 事件是由 a 中的脚本制定的函数,用以获取 b 中的某个全局变量。 需要将二者的 document.domian 同时设置为 kyrieliu.cn 即可完成这一次的跨域。
一个页面和从属于它的 iframe 之间可以互相读取和修改 URL,但还是有一定的前提:父窗口对子窗口进行 url 的读写时,随意;子窗口对父窗口的 url 进行读写时,受到同源策略的限制。所以在这种情况下,子窗口需要借助一个“代理窗口”去修改父窗口的 url。 通信的交互过程如上。 接下来再讨论为什么 hash 可以实现传递数据的需求。 对于每一个 url 来说,hash 就是 # 后面的部分,这一部分通常用来做当前页面的锚点定位,所以服务器(后端)是不会关心这一部分的,从而可以交给前端来搞一些“骚操作”。但也有一个不可避免的缺点:会造成一些不必要的 history 记录。
比如在 url 为 kyrieliu.cn/index.html 的页面 A 内 append 了一个 src 为 google.com/index.html 的 iframe。
parent.parent.location.hash = self.location.hash.substring(1)
将数据传递给 A这个方法就比较简洁明了:父窗口和子窗口都可以作为数据的发送方和接收方,且不需要考虑是否同源。还是用上面的栗子,比如现在需要从父窗口向子窗口发送数据:
// A.js
const iframe = document.querySelector('#iframe');
const targetOrigin = 'google.com';
iframe.contentWindow.postMessage('hello', targetOrigin);
// iframe.js
window.addEventListener('message', function(ev){
// 验证发送方
if (ev.origin === 'kyrieliu.cn') {
console.log(ev.data);
}
}, false);
这里注意 postMessage 的调用方式: whichWindow.postMessage(message, targetOrigin);
这是一种古老且稳定的跨域方式,兼容性好,但只支持获取数据(GET)。它的原理是:
<script>
的形式向后端发起请求,并在参数中告知将用于处理数据的函数名,同时在前端定义这个函数。CORS(Cross Origin Resource Sharing)的中心思想是:通过自定义的 HTTP Header 让浏览器和服务器进行“沟通”,决定本次请求的成功与否。 一般情况下,前端开发人员需要做的就是: