深入剖析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 条评论
登录 后参与评论

相关文章

来自专栏一个爱瞎折腾的程序猿

sqlserver使用存储过程跟踪SQL

USE [master] GO /****** Object: StoredProcedure [dbo].[sp_perfworkload_trace_s...

2170
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2232
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2626
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3255
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2627
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2727
来自专栏落花落雨不落叶

canvas画简单电路图

65611
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

2675
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

32610
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

4827

扫码关注云+社区