如何基于 iframe 解决跨域? 您所在的位置:网站首页 iframe跨域设置token 如何基于 iframe 解决跨域?

如何基于 iframe 解决跨域?

#如何基于 iframe 解决跨域?| 来源: 网络整理| 查看: 265

一般跨域听得比较多的方案是 Nginx 代理,CORS,而 JSONP 和 iframe 的跨域解决往往只在背八股文的时候出现,而且老是只给 JSONP 的实际操作手段,老是找不着 iframe 的实际操作,所以这篇文章就是介绍如何基于 iframe 解决跨域

您可以在线查看完整的示例源代码

跨域

什么是跨域,跨域定义太多了,我直接介绍哪些场景会有跨域,当请求路径和当前页面路径存在以下情况

协议不同,域名不同,端口不同

location.hash

阅前注意

http://localhost:3001: server 服务端 http://localhost:3000: client 客户端

这个方法主要是使用的 location.hash 去通信,iframe 的 src 属性不受跨域限制和中间页面解决(_vue-router 也有用到 location.hash_)

解决方案如下,需要跨域的页面,简称 client.html

请求 const getUsers = () => { let clientIframe = document.getElementById("clientIframe"); if (!clientIframe) { clientIframe = document.createElement("iframe"); clientIframe.id = "clientIframe"; clientIframe.style.display = "none"; clientIframe.src = "http://localhost:3001/data.html/#users"; document.body.appendChild(clientIframe); } else { clientIframe.src = "http://localhost:3001/data.html/#users"; } window.addEventListener("hashchange", function (e) { console.log("返回响应", location.hash.substring(1)); }); };

客户端封装一个包裹 iframe 的请求,方便重复请求

注:考虑到浏览器创建 DOM 的消耗过高,因此采用单一实例,有部分文章采用的是重复创建,由于作者眼界有限,如有错误望在评论区指出

其中 http://localhost:3001/data.html 是服务端提供的文件,由于和服务端同属一个域,因此在其中的请求不受跨域限制

// 初次加载 switch (location.hash) { case "#users": callback("users"); break; } // 重复调用 window.addEventListener("hashchange", function (e) { switch (location.hash) { case "#users": callback("users"); break; } }); /** * iframe 跨域回调 * @param {string} path 请求路径 */ function callback(path) { try { const xhr = new XMLHttpRequest(); xhr.open("GET", `http://localhost:3001/${path}`); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { // do something } } }; xhr.send(); } catch (e) { console.log(e); } }

内嵌 iframe 在请求到数据以后需要怎样和客户端通信呢?

http://localhost:3001/data.html 和 http://localhost:3000 通信难题

这个问题的解决方案其实就是通过 location.hash,每一个 iframe 拥有一个属性 parent

如果当前窗口是一个  ,  , 或者  ,则它的父窗口是嵌入它的那个窗口 - window.parent - MDN

但注意,由于 ie, chrome 的安全机制我们无法修改此处的 http://localhost:3001/data.html 的 parent.location.hash,因此需要借助一个中间页面,以 http://localhost:3000/proxy.html 代称,根据跨域定义,它和 http://localhost:3000 同源,下面给张图捋一捋三个 html 的关系

IMG

proxy.html 内容如下

// 初次加载 parent.parent.location.hash = self.location.hash.substring(3); // 重复调用 window.addEventListener("hashchange", function (e) { parent.parent.location.hash = self.location.hash.substring(3); });

http://localhost:3000/proxy.html 的 location.hash 和 http://localhost:3000/ 的 location.hash 是一样的

IMG

所以在 data.html 中的 do something 修改成以下内容

// ... if (xhr.status === 200) { // ie, chrome 下的安全机制无法修改 parent.location.hash // 所以要利用一个中间的代理 iframe let proxyIframe = document.getElementById("proxyIframe"); if (!proxyIframe) { proxyIframe = document.createElement("iframe"); proxyIframe.id = "proxyIframe"; proxyIframe.style.display = "none"; proxyIframe.src = "http://localhost:3000/proxy.html#" + Math.floor(Math.random() * 100) + xhr.response; document.body.appendChild(proxyIframe); } else { proxyIframe.src = "http://localhost:3000/proxy.html#" + Math.floor(Math.random() * 100) + xhr.response; } location.hash = ""; } // ...

响应返回加上随机数的原因是为了 proxy.html 能够触发 hashchange 事件,注意,前面说过http://localhost:3000/proxy.html 的 location.hash 和 http://localhost:3000/ 的 location.hash 是一样的,但在此处修改 proxyIframe 的 src 是不会影响 proxy.html 的 location.hash 同时也能触发 hashchange 事件,除此之外,客户端也需要按约定过滤随机数,即 self.location.hash.substring(3)

效果如下

29.gif

总结

你可以不懂但是不可以不会,该用到 JSONP 和 iframe 的时候你就可以拥有这个方向的思路,就拿 JSONP 来说,我以前一直以为是无用的八股,但后面实习时遇到一个公共接口不能使用 CORS 也不能使用 Nginx,想知道原因?原因如下

CORS: 公司老业务,运行很久很稳定,开发人员跑路了,只有上古文档,而且非同组沟通困难 Nginx: 不能直接上,需要知道接口的具体部署地址和库,而且有引用鉴权,同组对接后端尝试自行补写 Referrer,但最终失败

后面使用的 JSONP 解决,而 iframe 我想也有它合适的适用场景,就像这篇文章中提到的利用 iframe 引用公共视频播放器

参考资料 浅析api跨域的三种方案及iframe跨域的四种方案对比 - 古兰精 - 博客园 iframe跨域的几种常用方法 - SugarTurboS


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有