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节点的方法来实现完全跨域的通信。
 
3、JSONP(JSON with Padding)
„  JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
„  在JS中,通过<script>可以在页面上引入不同域上的JS脚本文件,jsonp正是利用这个特性来实现的。
 
  前端:
<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=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。

„$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载JS文件的形式来调用jsonp的回调函数
 
JSONP的优点是:
  它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,不需要XMLHttpRequest或ActiveX的支持。
„JSONP的缺点则是:
„  它只支持GET请求而不支持POST等其它类型的HTTP请求;
„  它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
 
4、window.name
    „window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的。
„  每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
  
实现跨域需要3个文件:
  a.com/app.html:应用页面。
  a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
„  b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。
 
  a.com/app.html
<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

„  window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源。
„  目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持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)

  „CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。
„  „CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
 
跨域方法:
<script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://b.com/new/",true);
    xhr.send();
</script>

注意:

„  需要服务器和浏览器的支持
„  例如PHP的响应页面顶端添加如下代码:
header("Access-Control-Allow-Origin:http://a.com");
„  表示接受来自a.com的跨域请求,"*"表示接受所有跨域请求
 
 
总结不同跨域方法所使用的途径:

跨域方法

iframe

script

other

window.domain

   

动态<script>

 

 

JSONP

 

 

window.name

   

window.postMessage

   

CORS

   

其他跨域方法:

„  1. flash (YUI IO)
„  2. 代理服务器
 
 
  
posted @ 2015-07-23 11:34  dong93  阅读(240)  评论(0编辑  收藏  举报