Javascript 跨域
JS跨域是指通过JS在不同的域之间进行数据传输或通信,比如用AJAX向一个不同的域请求数据,或者通过JS获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。
不同环境下JS的通信:
URL |
说明 |
是否允许通信 |
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 |
允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一域名下不同文件夹 |
允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不同端口 |
不允许 |
http://www.a.com/a.js https://www.a.com/b.Js |
同一域名,不同协议 |
不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名与域名对应的IP |
不允许 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不同 |
不允许 |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不同二级域名 |
不允许 |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不同域名 |
不允许 |
总结了一下,常见的跨域方法有一下几种:
1、document.domain
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。
具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。
http://www.a.com/a.html
document.domain = 'a.com'; var ifr = document.createElement('iframe'); ifr.src = 'http://script.a.com/b.html'; ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function(){ var doc = ifr.contentDocument || ifr.contentWindow.document; // 在这里操纵b.html,调用函数使用ifr.contentWindow.funcName console.log(doc); };
http://script.a.com/b.html
document.domain = 'a.com';
存在的问题:
一、安全性,当一个站点(script.a.com)被攻击后,另一个站点(www.a.com)会引起安全漏洞。
二、如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。
2、动态创建script
虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。
<script type="text/javascript"> function dosomething(jsondata){ //处理获得的json数据 } </script> <script src="http://a.com/data.php?callback=dosomething"> </script>
服务器端:
<?php $callback = $_GET['callback'];//得到回调函数名 $data = array('a','b','c');//要返回的数据 echo $callback.'('.json_encode($data).')'; //输出dosomething(['a','b','c']) ?>
JSONP by jQuery
<script type="text/javascript"> $.getJSON('http://a.com/data.php?callback=?',function(jsondata){ //处理获得的json数据 }); </script>
jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
<iframe id="data" src="http://b.com/data.html" style="display:none;" onload="getData()"> </iframe> <script> function getData() { var iframe = document.getElementById('data'); iframe.onload = function () { var data = iframe.contentWindow.name; console.log(data); } iframe.src = 'http://a.com/proxy.html'; } </script>
b.com/data.html
<script type="text/javascript"> window.name = 'data'; // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右 </script>
特点:
frame的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
5、HTML5 window.postMessage
postMessage(); otherWindow.postMessage(message, targetOrigin); //otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性; //message: 所要发送的数据,string类型。 //targetOrigin: 用于限制otherWindow,“*”表示不作限制
a.com/index.html
<iframe id="ifr" src="b.com/index.html"></iframe> <script type="text/javascript"> window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = 'http://b.com'; // 若写成'http://c.com'就不会执行postMessage了 ifr.contentWindow.postMessage('I was there!', targetOrigin); }; </script>
b.com/index.html
<script type="text/javascript"> window.addEventListener('message', function(event){ // 通过origin属性判断消息来源地址 if (event.origin == 'http://a.com') { alert(event.data); // 弹出"I was there!" alert(event.source); // 对a.com、index.html中window对象的引用 // 但由于同源策略,这里event.source不可以访问window对象 } }, false); </script>
6、跨域资源共享(CORS)
<script type="text/javascript"> var xhr = new XMLHttpRequest(); xhr.open("GET", "http://b.com/new/",true); xhr.send(); </script>
注意:
header("Access-Control-Allow-Origin:http://a.com");
跨域方法 |
iframe |
script |
other |
window.domain |
√ |
||
动态<script> |
√ |
||
JSONP |
√ |
||
window.name |
√ |
||
window.postMessage |
√ |
||
CORS |
√ |
其他跨域方法: