深入剖析iframe跨域问题

HTML5学堂:本文当中我们介绍了跨域的基本知识,讲解到了跨域的相关种类,并讲解了解决跨域中的一种方法——如何使用iframe跨域。讲解了iframe跨域的基本原理与流程,并配以实战~

利利的独白:跨域,是我们的课程中必不可少的一部分,但是我们一直都是在讲解JSONP的跨域方式,虽然也提到了iframe的跨域方式,但是由于时间因素,并没有办法放置到课程中。

本文仅仅讲明了iframe的跨域问题,想了解更多关于iframe标签的基本知识,直接发送 “iframe标签” 到 “HTML5学堂” 的微信。

什么是跨域

同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式。

跨域问题是浏览器同源策略限制,当前域名的JavaScript只能读取同域下的页面对象,这也是JavaScript出于安全方面的考虑

“话说,利利啊,能不能解释明白点?这么一坨理论,很难理解啊~~~” —— 我知道你是这么想的

通俗的来说,跨域可以理解为:从一个域名访问另一个域名,出于安全考虑,浏览器不允许这么做。

跨域的种类

什么时候我们认为发生了跨域呢?或者说什么情况下“浏览器”是不允许我们访问的呢?

不同域名 - 禁止

例子:http://www.baidu.com 与 http://www.h5course.com

域和子域 - 禁止

例子:http://www.baidu.com 与 http://play.baidu.com

同一域名不同端口 - 禁止

例子:http://www.h5course.com 与 http://www.h5course.com:8080

不同协议 - 禁止

例子:http://www.baidu.com 与 https://www.baidu.com

IP与IP对应的域名 - 禁止

iframe能够解决什么类型的跨域

主域相同,不同子域之间的跨域请求 例如:http://www.h5course.com/与http://baobao.h5course.com/

iframe实现跨域的基本原理与流程

基本原理

需求:希望在http://A.h5course.com/a.html访问http://B.h5course.com/data.php文件中的数据。

由于跨域,浏览器禁止,因此我们需要在http://A.h5course.com/a.html当中控制http://B.h5course.com/b.html访问http://B.h5course.com/data.php文件中的数据。

假设A域当中有一个a.html(虚拟路径为http://A.h5course.com/a.html),B域当中有一个b.html文件(虚拟路径为http://B.h5course.com/b.html),此时我们希望a.html能够访问到b.html。(为了防止记忆混乱,我们下面采用最简短的A、B域和a.html、b.html)

此时我们可以在a.html文件中,通过iframe引入b.html文件(即在a.html文件中引入b.html,引入的方式是iframe)。之后用b.html文件去访问b域,然后将访问结果,传递给a域中的a.html(传递过程就是通过iframe)。

iframe跨域的流程

1 创建iframe - 在a.html文件中,动态创建iframe元素/标签

2 视觉控制 - 为了让用户无法看到这个iframe元素/标签,需要使用CSS将其移出可视区

3 设置domain - 为了保证a.html与b.html的访问能够顺畅进行,需要为两个文件均定义domain,即将document.domain设置为“主域名”

4 数据操作与传递 - 在a.html文件中编写好AJAX申请,而这个AJAX的内容就是b.html要负责执行的内容;除了编写好AJAX申请之外,还需要在a.html文件“命令”b.html去执行(在当前这个步骤当中,b.html文件不需要书写任何代码,b.html不需要写代码,b.html不写代码[重要的事说三遍])

iframe跨域的代码实现

重申需求:希望在http://A.h5course.com/a.html访问http://B.h5course.com/data.php文件中的数据。

由于跨域,浏览器禁止,因此我们需要在http://A.h5course.com/a.html当中控制http://B.h5course.com/b.html访问http://B.h5course.com/data.php文件中的数据

HTML5学堂友情提示:本代码基于jQuery.js而实现,因此,在书写本代码之前,请先引入jQuery.js。

1 创建iframe标签 + 2 视觉控制

操作位置:A域中的a.html

<script>
    function addIframe() {
        var newIframe = '<iframe id="newframe" src="B域/b.html" name="postframe" style="position: absolute; left: -9999px; top: 0; width: 0; height: 0;" />';
        $('body').append(newIframe);
    }addIframe();
</script>

Tips:iframe标签中的src地址要书写的是B域的b.html(也就是我们跨域时需要调用的文件)。

Tips:针对iframe标签的style样式设置,是为了将这个标签移出我们的网页可视区域。换句话说,我们在HTML当中新增了一个标签,在结构显示上必然会出现这个东西,但是,对于我们来说,我们希望iframe并不被用户看到,因此就需要进行样式的处理。

Tips:创建一个标签之后并不代表这个标签就会出现在网页当中,因此我们需要使用到DOM操作(append),将这个新生成的标签添加到body当中。

3 设置domain

操作位置:A域中的a.html和B域的b.html(双方均需要设置)

A域中的a.html:在$('body').append(newIframe);代码的后面直接添加如下代码:

document.domain = 'h5course.com';

B域中的b.html添加如下代码:

<script src="js/jquery.js"></script>
<script>
    document.domain = 'h5course.com';
</script>

Tips:注意设置域的这段代码处于addIframe这个功能函数当中。

Tips:注意我们之前提到的,两个文件的虚拟路径,分别为http://A.h5course.com/a.html; http://B.h5course.com/b.html。因此此处使用“h5course.com”

Tips:可能你会问,b.html没有使用到jQuery,利利你为何还要加JQ的引入呢?此处主要是由于我们之后的操作,是需要通过A域,让B域去执行代码,A域提出的要求中的命令涉及到jQuery(so,别急,看我们的第四步)

4 数据操作与传递

!!!~重头戏来喽~!!!

由于本步骤比较复杂,所以我们拆解开,一步步给大家讲解。

4.1 在a.html文件当中获取b.html文件的jQuery对象

想要让a控制b去做什么,首先得获取到b(就如同我们“希望控制一个标签样式,就先得通过选择器选择到;想要为某个标签添加事件,就先得通过getElementById的方式获取到标签”一样)。

获取到b.html文件中的jQuery对象的代码是:

$('#newframe')[0].contentWindow.$;

此处需要注意两点:newframe这个id是我们在创建的时候起好的,各位可以根据自己代码的具体情况进行修改;为$('#newframe')添加[0]的主要目的是:contentWindow是原生JS的属性,JQ和原生JS是不能混用的,此时我们需要将JQ转换为原生。

对于这段代码,添加到addIframe的什么地方呢?

我们一起缕一下逻辑:我们需要先创建一个iframe标签,之后当这个标签加载完成之后,才应该去获取这个标签里的页面的JQ对象。如果不遵循这个逻辑,我们是无法拿到这个对象的,因此代码就变成了这样~~~

<script>
    var iframeJquery = null;    // 用于存储iframe中的b.html的jQuery对象
    function addIframe() {
        var newIframe = '<iframe id="newframe" src="B域/b.html" name="postframe" style="position: absolute; left: -9999px; top: 0; width: 0; height: 0;" />';
        $('body').append(newIframe);
        document.domain = 'h5course.com';
        $('#newIframe').on('load', function(){
            iframeJquery = $('#newframe')[0].contentWindow.$;
        })
    }addIframe();
</script>

4.2 在获取b.html的对象之后,要执行一些代码

我们获取b.html中的JQ对象的目的,是通过a.html让b.html去访问B域当中的数据。因此我们必须通过a.html命令b.html去做什么事情。这也就要求我们需要在创建addIframe时为它传递一个参数(函数),而在获取b.html的jQuery对象之后执行这个函数。

再重复一遍:需要在“创建addIframe时为它传递一个参数(函数),而在获取b.html的jQuery对象之后执行这个函数”

<script>
    var iframeJquery = null;    // 用于存储iframe中的b.html的jQuery对象
    function addIframe(cb) {
        var newIframe = '<iframe id="newframe" src="B域/b.html" name="postframe" style="position: absolute; left: -9999px; top: 0; width: 0; height: 0;" />';
        $('body').append(newIframe);
        document.domain = 'h5course.com';
        $('#newIframe').on('load', function(){
            iframeJquery = $('#newframe')[0].contentWindow.$;
            cb();
        })
    }addIframe();
</script>

主要变化:在addIframe函数中添加了一个参数,在获取jQuery对象之后执行了这个参数(注意:这个参数是函数)。


4.3 在a.html中书写想要b.html执行的内容

打起精神来,最后一步啦~!!!

截止到目前,我们已经把主要功能搭建完成,就差定义具体需要“b.html要执行的代码”了,简言之——调用addIframe,并传入参数即可。如下代码

<script>
    var iframeJquery = null;    // 用于存储iframe中的b.html的jQuery对象
    function addIframe(cb) {
        var newIframe = '<iframe id="newframe" src="B域/b.html" name="postframe" style="position: absolute; left: -9999px; top: 0; width: 0; height: 0;" />';
        $('body').append(newIframe);
        document.domain = 'h5course.com';
        $('#newIframe').on('load', function(){
            iframeJquery = $('#newframe')[0].contentWindow.$;
            cb();
        })
    }
    // 我们希望b.html去调用http://B.h5course.com/data.php
    // 将获取到的数据呈现在a.html文件中$('.wrap')当中
    addIframe(function() {
        iframeJquery.ajax({
            url: 'http://B.h5course.com/data.php',
            type: 'GET',
            success: function(data) {
                $('.wrap').html(data);
            }
        });
    });
</script>

如上代码书写http://A.h5course.com/a.html当中控制http://B.h5course.com/b.html访问http://B.h5course.com/data.php文件中的数据。

如果还想了解AJAX的跨域相关问题,直接发送 “AJAX跨域” 到 “HTML5学堂” 的微信。

HTML5小编-利利&堡堡 耗时11.0h

原文发布于微信公众号 - HTML5学堂(h5course-com)

原文发表时间:2016-04-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开源优测

Python Selenium设计模式-POM

前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享,以便大家在实践中对POM的特点、应用场景和核心思想有一定的理解和掌握。...

2626
来自专栏守候书阁

webpack+vue项目实战(三,配置功能操作页和组件的按需加载)

上篇文章(webpack+vue项目实战(二,开发管理系统主页面)),实现了,侧边栏的一个操作,点击侧边栏的一些操作,最重要的就是路由的切换。看了上一篇的伙伴也...

652
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(十二):错误信息提示

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

61
来自专栏IMWeb前端团队

图片上传前预处理,等比缩放、裁剪 (html5 + canvas)

本文作者:IMWeb capricorncd 原文出处:IMWeb社区 未经同意,禁止转载 ? Image pre processing for up...

2546
来自专栏前端新视界

构建通用的 React 和 Node 应用

原文:Build a universal React and Node App 演示:https://judo-heroes.herokuapp.com/ 译者...

2547
来自专栏从零开始学自动化测试

Selenium2+python自动化41-绕过验证码(add_cookie)

前言 验证码这种问题是比较头疼的,对于验证码的处理,不要去想破解方法,这个验证码本来就是为了防止别人自动化登录的。如果你能破解,说明你们公司的验证码安全级别不高...

2626
来自专栏开源优测

Python Selenium设计模式-POM

前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享,以便大家在实践中对POM的特点、应用场景和核心思想有一定的理解和掌握。...

3477
来自专栏计算机编程

ionic4 -- angular 跳转页面

ionic4 与前辈们最大的不同就是通过angular引入了route,这样每次跳转的时候只需要直接跳转对应的路由地址就可以了,给了路由器上的解耦,也解决了原来...

892
来自专栏前端架构与工程

Node.js建站笔记-使用react和react-router取代Backbone

斟酌之后,决定在《嗨猫》项目中引入react,整体项目偏重spa模式,舍弃部分server端的模板渲染,将一部分渲染工作交给前端react实现。 react拥有...

2009
来自专栏开发实战

swagger-bootstrap-ui 1.7.5 发布,Swagger前端 UI 实现

swagger-bootstrap-ui 1.7.5 发布了。swagger-bootstrap-ui 是 Swagger 的前端 UI 实现,目的是替换 Sw...

1283

扫描关注云+社区