iframe 跨域问题解决方案 利用window.name+iframe跨域获取数据详解
详解
前文提到用jsonp的方式来跨域获取数据,本文为大家介绍下如何利用window.name+iframe跨域获取数据。
首先我们要简单了解下window.name和iframe的相关知识。iframe是html的一个标签,可以在网页中创建内联框架,有个src属性(指向文件地址,html、php等)可以选择内联框架的内容,可以看个例子(猛戳这里),大概了解下就行了。window.name(一般在js代码里出现)的值不是一个普通的全局变量,而是当前窗口的名字,这里要注意的是每个iframe都有包裹它的window,而这个window是top window的子窗口,而它自然也有window.name的属性,window.name属性的神奇之处在于name 值在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。
跨域解决方案似乎可以呼之欲出了,假设index.html页面请求远端服务器的数据,我们在该页面下新建一个iframe标签,该iframe的src属性指向服务器文件地址(利用iframe标签的跨域能力),服务器文件里设置好window.name的值(也就是该iframe的contentWindow的name值),然后在index.html里读取该iframe的window.name值,一切似乎水到渠成,代码如下:
<script type="text/javascript">
iframe = document.createElement('iframe'),
iframe.src = 'http://localhost:8080/data.php';
document.body.appendChild(iframe);
iframe.onload = function() {
console.log(iframe.contentWindow.name)
};
</script>
</body>
<?php
echo '<script> window.name = "{\"name\":\"hanzichi\", \"age\":10}"; </script>'
?>
但是不幸的是,报错了..
提示啥协议、主机、端口三者要一致,这不是赤裸裸地告诉你跨域了么!为什么会这样,因为规定如果index.html页面和和该页面里的iframe框架的src如果不同源,则也无法操作框架里的任何东西,所以就取不到iframe框架的name值了,告诉你我们不是一家的,你也休想得到我这里的数据。既然要同源,那就换个src去指,前面说了无论怎样加载window.name值都不会变化,于是我们在index.html相同目录下,新建了个proxy.html的空页面,修改代码如下:
<body>
<script type="text/javascript">
iframe = document.createElement('iframe'),
iframe.src = 'http://localhost:8080/data.php';
document.body.appendChild(iframe);
iframe.onload = function() {
iframe.src = 'http://localhost:81/cross-domain/proxy.html';
console.log(iframe.contentWindow.name)
};
</script>
</body>
理想似乎很美好,在iframe载入过程中,迅速重置iframe.src的指向,使之与index.html同源,那么index页面就能去获取它的name值了!但是现实是残酷的,iframe在现实中的表现是一直不停地刷新,也很好理解,每次触发onload时间后,重置src,相当于重新载入页面,又触发onload事件,于是就不停地刷新了(但是需要的数据还是能输出的)。修改后代码如下:
<body>
<script type="text/javascript">
iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0; iframe.onload = function() {
if(state === 1) {
var data = JSON.parse(iframe.contentWindow.name);
console.log(data);
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else if(state === 0) {
state = 1;
iframe.contentWindow.location = 'http://localhost:81/cross-domain/proxy.html';
}
}; iframe.src = 'http://localhost:8080/data.php';
document.body.appendChild(iframe);
</script>
</body>
总结
能使用这种方式跨域,有几个条件必不可少。
- iframe标签的跨域能力
- window.name属性值在文档刷新后依旧存在的能力
再简单了解下window和contentWindow的一些知识。浏览器就会为原始文档创建一个 window 对象,再为每个框架(iframe)创建额外的 window 对象。这些额外的对象是原始窗口的子窗口,可能被原始窗口中发生的事件所影响。例如,关闭原始窗口将导致关闭全部子窗口。contentWindow属性是指指定的frame或者iframe所在的window对象。
使用方法
很多人或许只关注使用方法,而对原理不怎么感冒。此法相对于jsonp复杂,使用方法也更复杂些。
服务端一般输出一段js代码,例如下面这样:
<?php
echo '<script> window.name = "{\"name\":\"hanzichi\", \"age\":10}"; </script>'
?>
window.name的值是字符串形式,也是需要传递给客户端的数据(当然如果有需要服务端也可以先处理传过来的数据,这里仅为只有数据回传),有需要自己再去解析(如字符串->json数据)。
index.html页面,我把方法封装成了函数:
<body>
<script type="text/javascript">
function crossDomain(url, fn) {
iframe = document.createElement('iframe');
iframe.style.display = 'none';
var state = 0; iframe.onload = function() {
if(state === 1) {
fn(iframe.contentWindow.name);
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
} else if(state === 0) {
state = 1;
iframe.contentWindow.location = 'http://localhost:81/cross-domain/proxy.html';
}
}; iframe.src = url;
document.body.appendChild(iframe);
} // 调用
// 服务器地址
var url = 'http://localhost:8080/data.php';
crossDomain(url, function(data) { // 处理数据 data就是window.name的值(string)
var data = JSON.parse(iframe.contentWindow.name);
console.log(data);
});
</script>
</body>
这里还有一点小问题,ie的兼容(iframe的onload ie下似乎要用attachEvent,以及json对于ie的兼容),有兴趣的朋友自己去研究了(可以参考下参考文章);另外proxy代理页面可以没有这个文件,会报404但是不影响功能(但是路径一定要和index页面同源)。
还有一点值得思考的是iframe的src重定向的时候,代码:
iframe.contentWindow.location = 'http://localhost:81/cross-domain/proxy.html';
这时iframe.src指向的还是服务端页面,这里的代码如果用iframe.src = 'http://localhost:81/cross-domain/proxy.html';代替也是可以输出结果的,聪明的你知道区别吗?
参考
程序员都应该学点算法:https://github.com/hanzichi/leetcode
了解博主韩子迟:http://www.cnblogs.com/zichi/p/about.html
GitHub:https://github.com/hanzichi Follow 楼主给楼主更多写作的动力~
iframe 跨域问题解决方案 利用window.name+iframe跨域获取数据详解的更多相关文章
- 利用window.name+iframe跨域获取数据详解
详解 前文提到用jsonp的方式来跨域获取数据,本文为大家介绍下如何利用window.name+iframe跨域获取数据. 首先我们要简单了解下window.name和iframe的相关知识.ifra ...
- 利用location.hash+iframe跨域获取数据详解
前言 如果看懂了前文利用window.name+iframe跨域获取数据,那么此文也就很好理解了.一样都是动态插入一个iframe,然后把iframe的src指向服务端地址,而服务端同样都是输出一段j ...
- 解决Iframe跨域高度自适应,利用window.postMessage()实现跨域消息传递页面高度(JavaScript)
在iframe跨域引用高度自适应这块写的js方式都试了不管用,最终使用的是window.postMessage() 跨域获取高度 传递信息 1.首先,在主页面上使用iframe引入子页面:也就是A.h ...
- Window下PHP三种运行方式图文详解,window下的php是不是单进程的?
Window下PHP三种运行方式图文详解,window下的php是不是单进程的? PHP运行目前为止主要有三种方式: a.以模块加载的方式运行,初学者可能不容易理解,其实就是将PHP集成到Apache ...
- 利用rtklib处理GPS以及北斗数据详解
利用rtklib开源代码处理GPS以及北斗数据详解 在GNSS领域最基础的工作是这些GNSS系统的定位工作,对于绝大多数研究者,自己着手完成这些工作是一个"鸡肋":完全独立设计的话 ...
- 利用window.name+iframe跨域获取接口数据
最近做了一个表单广告,需要从接口读取数据,做完发现谷歌火狐下正常,360兼容和IE浏览器无法获取数据,以下是鲜明的对比: 调试发现报错了: 然后开发把接口改成支持windowname,一开始 ...
- PHP下ajax跨域的解决方案之window.name
原理核心:window对象的name属性是一个很特别的属性,当该window的location变化,然后重新加载,它的name属性可以依然保持不变. 依此原理,我们可以在页面A中用iframe加载其他 ...
- PHP下ajax跨子域的解决方案之document.domain+iframe
对于主域相同,子域不同,我们可以设置相同的document.domain来欺骗浏览器,达到跨子域的效果. 例如:我们有两个域名:www.a.com 和 img.a.com 在www.a.com下有 ...
- Asp.NetMVC利用LigerUI搭建一个简单的后台管理详解(函登录验证)
上一篇 Asp.Net 中Grid详解两种方法使用LigerUI加载数据库数据填充数据分页 了解了LigerUI 中Grid的基本用法 现在结合上一篇的内容做一个简单的后台管理,当然也有前台的页面 ...
随机推荐
- TextSwitcher实现文本自动垂直滚动
实现功能:用TextSwitcher实现文本自动垂直滚动,类似淘宝首页广告条. 实现效果: 注意:由于网上横向滚动的例子比较多,所以这里通过垂直的例子演示. 实现步骤:1.extends TextSw ...
- MVC Route路由
由于某些原因,需要默认区域,所以需要对路由进行设置 具体实现如下: using System.Web; using System.Web.Mvc; using System.Web.Routing; ...
- poj_1204 Trie图
题目大意 给出一个RxC的字符组成的puzzle,中间可以从左向右,从右到左,从上到下,从下到上,从左上到右下,从右下到左上,从左下到右上,从右上到左下,八个方向进行查找字符串. 给出M个字符 ...
- redis 之初体验(window)
1 下载window版本的redis :https://github.com/MSOpenTech/redis/releases 2 解压压缩包.我的放在了E盘: E:/redis 3 程序,输入cm ...
- JDBC处理文本和二进制文件
JDBC支持文本(CLOB)和二进制(BLOB)文件的处理,比如要往数据库里存取文章或者图片.这都是用流的思想来解决的. 来两个Demo看看JDBC是怎么操作文本和二进制文件的. CLOB: pack ...
- TCP异常关闭研究分析
版权声明:本文由谢代斌原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108 来源:腾云阁 https://www.qclo ...
- str += "a" + "b" & str = str + "a" + "b"的性能比较
str += "a" + "b"在浏览器中的执行过程: 1.创建临时字符串, 2.将临时字符串设置为“ab”, 3.将临时字符串和str进行连接, 4.将结果赋 ...
- Unity3D笔记八 Unity生命周期及动画学习
Unity脚本从唤醒到销毁有着一套比较完善的生命周期,添加任何脚本都必须遵守自身生命周期法则.下面介绍一下生命周期中由系统自身调用的几个比较重要的方法. Update(){}.正常更新,用于更新逻 ...
- Spring MVC 框架学习
一.spirng的简介 Spring是一个开源框架,它由Rod Johnson创建.它是为了解决企业应用开发的复杂性而创建的.Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情. ...
- chorme快捷键
Chrome窗口和标签页快捷键:Ctrl+N 打开新窗口 Ctrl+T 打开新标签页 Ctrl+Shift+N 在隐身模式下打开新窗口 Ctrl+O,然后选择文件 在谷歌浏览器中打开计算机上的文件 按 ...