前端跨域的几种方式
来源:互联网 发布:淘宝店怎么提升销量 编辑:程序博客网 时间:2024/05/01 17:55
前言
受浏览器同源策略的限制,本域的js不能操作其他域的页面对象(比如DOM)。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。所以我们要通过一些方法使本域的js能够操作其他域的页面对象或者使其他域的js能操作本域的页面对象(iframe之间)。
这里需要明确的一点是:所谓的域跟js的存放服务器没有关系,比如baidu.com的页面加载了google.com的js,那么此js的所在域是baidu.com而不是google.com。也就是说,此时该js能操作baidu.com的页面对象,而不能操作google.com的页面对象。
跨域的方法总结
单向跨域(一般用于获取数据)
一、使用JSONP跨域
原理:因为通过script标签引入的js是不受同源策略的限制的(正如前文提到的baidu.com的页面加载了google.com的js)。所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如PHP,jsp等)的文件,此文件返回一个js函数的调用,如返回JSONP_getUsers(["paco","john","lili"]),也就是说此文件返回的结果调用了JSONP_getUsers函数,并且把["paco","john","lili"]传进去,这个["paco","john","lili"]是一个用户列表。那么如果此时我们的页面中有一个JSONP_getUsers函数,那么JSONP_getUsers就被调用到,并且传入了用户列表。此时就实现了在本域获取其他域数据的功能,也就是跨域。
实现例子如下:
前端引入远程js并定义好JSONP_getUsers函数,注意需要先定义好JSONP_getUsers函数,避免在远程js加载完成并调用JSONP_getUsers时,此函数不存在:
//本域为baidu.com <script> function JSONP_getUsers(users){ console.dir(users); } </script> //加载google.com的getUsers.php <script src="http://www.google.com/getUsers.php"></script>需要google.com提供支持,getUsers.php代码如下:
<?php> echo 'JSONP_getUsers(["paco","john","lili"])';//返回一个js函数的调用 ?>JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。可以看出来JSONP跨域一般用于获取其他域的数据。
一般能够用JSONP实现跨域就用JSONP实现,这也是前端用的最多的跨域方法。
二、动态创建script标签
这种方法其实是JSONP跨域的简化版,JSONP只是在此基础上加入了回调函数。
比如上例中的getUsers.php返回的如果不是一个js函数的调用,而是一个js变量,如:
<?php> echo 'var users=["paco","john","lili"]';//返回一个js变量users ?>三、flash URLLoader
flash有自己的一套安全策略,服务器可以通过crossdomain.xml文件来声明能被哪些域的SWF文件访问,SWF也可以通过API来确定自身能被哪些域的SWF加载。当跨域访问资源时,例如从域baidu.com请求域google.com上的数据,我们可以借助flash来发送HTTP请求。首先,修改域google.com上的crossdomain.xml(一般存放在根目录,如果没有需要手动创建) ,把baidu.com加入到白名单。其次,通过Flash URLLoader发送HTTP请求,最后,通过Flash API把响应结果传递给JavaScript。Flash URLLoader是一种很普遍的跨域解决方案,不过需要支持iOS的话,这个方案就不可行了。
四、Access Control
此跨域方法目前只在很少的浏览器中得以支持,这些浏览器可以发送一个跨域的HTTP请求(Firefox, Google Chrome等通过XMLHTTPRequest实现,IE8下通过XDomainRequest实现),请求的响应必须包含一个Access- Control-Allow-Origin的HTTP响应头,该响应头声明了请求域的可访问权限。例如baidu.com对google.com下的getUsers.php发送了一个跨域的HTTP请求(通过ajax),那么getUsers.php必须加入如下的响应头:
header("Access-Control-Allow-Origin: http://www.baidu.com");//表示允许baidu.com跨域请求本文件
try { parent.location.hash = 'data'; } catch (e) { // ie、chrome的安全机制无法修改parent.location.hash, var ifrproxy = document.createElement('iframe'); ifrproxy.style.display = 'none'; ifrproxy.src = "http://www.baidu.com/proxy.html#data"; document.body.appendChild(ifrproxy); }proxy.html页面的关键代码如下:
//因为parent.parent(即baidu.com/a.html)和baidu.com/proxy.html属于同一个域,所以可以改变其location.hash的值 parent.parent.location.hash = self.location.hash.substring(1);九、使用HTML5的postMessage方法(两个iframe之间或者两个页面之间)
高级浏览器Internet Explorer 8+, chrome,Firefox , Opera 和 Safari 都将支持这个功能。这个功能主要包括接受信息的"message"事件和发送消息的"postMessage"方法。比如baidu.com域的A页面通过iframe嵌入了一个google.com域的B页面,可以通过以下方法实现A和B的通信
A页面通过postMessage方法发送消息:
window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = "http://www.google.com"; ifr.contentWindow.postMessage('hello world!', targetOrigin); };postMessage的使用方法:
otherWindow.postMessage(message, targetOrigin);
otherWindow: 指目标窗口,也就是给哪个window发消息,是 window.frames 属性的成员或者由 window.open 方法创建的窗口
message: 是要发送的消息,类型为 String、Object (IE8、9 不支持)
targetOrigin: 是限定消息接收范围,不限制请使用 '*'
B页面通过message事件监听并接受消息:
var onmessage = function (event) { var data = event.data;//消息 var origin = event.origin;//消息来源地址 var source = event.source;//源Window对象 if(origin=="http://www.baidu.com"){ console.log(data);//hello world! } }; if (typeof window.addEventListener != 'undefined') { window.addEventListener('message', onmessage, false); } else if (typeof window.attachEvent != 'undefined') { //for ie window.attachEvent('onmessage', onmessage); }
同理,也可以B页面发送消息,然后A页面监听并接受消息。
总结
跨域的方法很多,不同的应用场景我们都可以找到一个最合适的解决方案。比如单向的数据请求,我们应该优先选择JSONP或者window.name,双向通信优先采取location.hash,在未与数据提供方达成通信协议的情况下我们也可以用server proxy的方式来抓取数据。
- 前端跨域的几种方式
- 浅谈前端跨域的几种解决方式
- SSH前端分页的几种方式
- 前端数字格式化的几种方式
- web前端页面取值的几种方式
- web前端页面取值的几种方式
- html前端几种加密方式的整理
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- java web 前端访问后端的几种方式
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 前端HTML5几种存储方式的总结
- 【前端Js】原型继承的几种方式
- RocketMQ原理以及源码解析目录介绍
- ScrollView下的UITextField系统手写输入法造成崩溃的解决办法
- php的4种常用运行方式
- Android上实现一个简单的天气预报APP(十三) 导航ViewPager
- 分区表更改默认表空间及移动现有分区到指定表空间
- 前端跨域的几种方式
- Git与TortoiseGit基本操作
- swap函数的泛型
- android 解决部分手机连接热点wifi导致被切换,enablenetwork(netID, true)无效的问题
- 判断用户输入的银行卡号是否正确--基于Luhn算法的格式校验
- UDP接收实例
- Android前端判断敏感词汇
- java.util.concurrent之ForkJoin
- Windows下查询域名的DNS TXT记录的命令