首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【JS应用】Iframe 解决跨域

【JS应用】Iframe 解决跨域

作者头像
神仙朱
发布2019-11-07 15:57:18
13.9K0
发布2019-11-07 15:57:18
举报
因为学习了腾讯出的前端进阶课程,所以打算把课程内容都总结一遍。有些都是很普通很常见的知识,但是为了巩固自己的知识面,梳理自己的知识树,所以每个知识点都会写成文章,所有文章都会放在公众号右下角的前端进阶课程总结中~~~也希望能够帮助到需要的人~~

跨域的东西, 简直不要接触太多,网上相关内容一抓一大把,但是突然学习到一个关于前端解决跨域的方式

就是 利用 iframe

不管你有没有了解过,反正我没有

我觉得很有用并且容易忘,所以我记录下来哈哈哈

下面会分三块内容进行描述

1、基本原理

2、简单模拟

2、封装的函数

3、封装函数实战

解决场景

现在我们在 a.com 的域名下有一个页面

我们要请求 b.com 下的一个接口,很明显是会跨域的,无法直接请求

今天我们使用 iframe 来解决这个问题

基本原理

1、需要三个页面

两个同域(a.com)的 页面,一个和接口同域的 页面(b.com)

其中一个页面是父页面,也就是真正的内容页,展示数据的

另外两个作为子页面,是辅助父页面请求跨域数据用的,不会显示在页面中

2、利用全局变量 window.name 存储数据

父子页面利用 window.name 进行通信,但是前提是同域

当 父子页面不同域的时候,父子无法访问对方 window.name

但是,如果是同级页面切换,就算是不同域,window.name 也是可以访问的

3、数据请求

现在请求 b.com 的接口,所以只能在 b.com 下的页面(这个是子页面)进行请求

请求成功后,保存在当前的 window.name 中

4、页面跳转

上一步保存完数据之后,由 b.com 页面 跳到 a.com 页面

此时 a.com 页面就能通过 window.name 拿到 b.com 保存过的数据啦

5、给父页面传递数据

上面那个 a.com 页面是辅助页,拿到数据之后,需要传递给真正需要数据的父页面(同样是 a.com 下)

大概了解之后,我们来说一下简单流程

现在有 a.com 下的内容页 A,需要请求接口 b.com/xxxx,但是跨域

1、内容页 A 嵌入一个隐藏 iframe,iframe 加载 b.com 下的辅助页面 B

2、辅助页面B 开始请求接口 b.com/xxx,请求成功,存放到 window.name

3、隐藏 iframe 由页面B 跳转到 a.com 下另一个辅助页(页面C)

4、页面C 读取到 B存放的 window.name,然后传递给 父页面A

5、父页面A 拿到 数据,用于展示在页面上

简单模拟

现在我启动了两个服务

1、localhost:3001 下有 a.html 和 c.html

a.html 是内容页,需要使用数据的终端页(以下简称A)

c.html 是辅助页(以下简称C)

2、localhost:3002 下有 b.html

b.html 也是辅助页,用于请求数据(以下简称B)

内容页 A

在 A 中,使用 iframe 嵌入了 B,并且全局设置了一个函数 getData

这个函数的作用是,为了给 C页面调用,传入接口的数据的

window.getData=function(data){

辅助页 B

B 页面当然是用于请求接口了,这里使用 定时器模拟接口,请求成功后跳转到 C

<body>

    我是B页面
    <script>
        console.log("B页面开始请求接口")

辅助页 C

B 请求完,跳到C 之后,C 拿到 window.name,然后调用 A 的方法 getData,并且把数据传过去

parent.getData(window.name)

没错,这就完成了 iframe 解决跨域的问题,但是实际上并不会这么做,肯定是封装得更加适用一些

详情就看下面吧

封装函数

经过上面的说明,我们首先要明确我们的目的

1、iframe

2、两个辅助页

3、数据回调

所以我们封装的函数必须要满足这几个东西

首先,封装一个函数创建 iframe 插入 body 中,并且转到传入的 url

function createIframe (url) {

很简单,都能看懂

之后,我们需要在 url 上拼接参数,所以我们需要在封装一个 url 相关的函数

为什么需要拼接参数?

比如请求的接口需要某些参数,这些参数是父页面提供的,所以就只能把这些参数放到 iframe 的 url 上以便通信

拼接 url 函数

function parseUrl (url, param) {

当时放在 url 上的参数,是要经过转义的,比如不能出现中文,所以需要多一个函数用于格式化参数

function serialize (data) {

那么现在就万事俱备,只欠主菜了,马上来看

function cross (option, callback) {

在这个函数中,解决了我们一开始提到的两个问题

1、数据回调

2、两个辅助页

很明显,这个函数是给我们的父页面调用的啦

首先,cross 函数接收两个参数,options 和 callback,一个个解释

options

是一个对象,包含下面四个字段

targetUrl

用于请求接口,跟接口同域那个辅助子页面

skipUrl

请求接口成功后,跳转到的那个子页面

data

请求接口时需要传递的参数

url

需要进行请求的接口名

callback

很明显,这个回调,也就是接口请求完成,跳转完成之后会触发的

但是并不是直接触发,而是包装了一层,你看其中这段

var funcName = getFunctionName()

主要作用还是像我们模拟中的一样,在父页面中注册一个函数,给子页面传递数据用

但是这个函数注册就有点意思了,因为是全局的,非常害怕全局污染和重名,所以这里弄了一个随机生成函数名的函数 getFunctionName,如下

function getFunctionName () {

但是,函数名是随机的,子页面怎么知道我要调用那个函数?

子页面:我不知道函数名字啊!!!!

所以需要把函数名字也传递

怎么传递?

放到 url 上,然后子页面就可以直接从 url 上拿参数,并取其中的字段 parentFunc ,就可以知道函数名啦

优化

随着请求越来越多,生成的全局随机函数肯定会越来越多,并且是一次性的,不会再被使用,留着根本没用,还占用资源

所以我们最好手动清除他,所以你看到在设置全局函数时,回调执行完之后就执行设置为 null

window[funcName] = function (response) {

没错,封装的函数我们已经看完了,我们还是有必要来看下怎么使用的啊

封装函数的实践

在这里我先出一个大王函数,用于获取链接参数的,直接得到对象的

作用如下

然后就到我们的正文了

首先,我们的内容页率先登场,并且调用 cross 表示调用接口

targetUrl: 'http://127.0.0.1:3002/b.html',

接着,到了我们要请求接口的B 页面

拿到 url 上的请求接口和请求参数,调用 ajax

调用成功后,拿到 url 上的 跳转链接 skipUrl,直接跳过去,并且带上参数 parsetFunc

因为C 页面中,需要知道函数名,所以这里必须带上

ajax({

那么现在就只剩下我们的C 页面了

从url 上获取到函数名,然后拿到 父页面的 window(也就是 parent)

直接调用,并且传入 window.name

这样,整个流程就走完了

parent[param.parentFuc](window.name);

不过说真的,这种方法也就作为一个备胎方法,大家熟悉熟悉知道一下就好了,毕竟项目中也不太可能用到

不过面试可能会问哈哈,多掌握点总是没错的

最后

鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵,如果有任何描述不当的地方,欢迎后台联系本人,领取红包

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 神仙朱 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档