javascript 跨域访问

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。因为同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。

下表给出了相对 http://site.baidu.com/file/index.html 同源检测的示例:

序号 URL结果原因
http://site.baidu.com/file/inner/1.html 成功 同一域名
2 http://site.baidu.com/file2/2.html 成功 同一域名不同文件夹
3 https://site.baidu.com/secure.html 失败 不同协议 ( https )
4 http://site.baidu.com:81/file/etc.html 失败 不同端口 ( 81 )
5 http://wiki.baidu.com/file/other.html 失败 不同主机 ( wike)

1、主域相同的跨域


主域相同的跨域

document.domain的场景只适用于不同子域的框架间的交互,及主域必须相同的不同源。

页面可能会更改其自己的来源,但有一些限制。脚本可以将 document.domain的值设置为其当前域或其当前域的超级域。如果将其设置为其当前域的超级域,则较短的域将用于后续原始检查。例如,假设文档中的一个脚本在 http://site.baidu.com/file/2.html 执行以下语句:

 document.domain = "baidu.com";

这条语句执行之后,页面将会成功地通过对 http://baidu.com/file/index.html 的同源检测。

//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
    alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};

//script.a.com上的b.html

document.domain = 'a.com';

注:

1. 某一页面的domain默认等于window.location.hostname。

2. 主域名是不带www的域名,例如a.com,主域名前面带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。

3. domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。

4. 使用document.domain允许子域安全访问其父域时,需要设置document域在父域和子域中具有相同的值。这是必要的,即使这样做只是将父域设置回其原始值。否则可能会导致权限错误。这里都是a.com。

2. 动态创建script

虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。具体的做法可以参考YUI的Get Utility

这里判断script节点加载完毕还是蛮有意思的:ie只能通过script的readystatechange属性,其它浏览器是script的load事件。以下是部分判断script加载完毕的方法。

js.onload = js.onreadystatechange = function() {
    if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
        // callback在此处执行
        js.onload = js.onreadystatechange = null;
    }
};

 优点:简单适用,老式浏览器全部支持,服务器改造小。不需要XMLHttpRequest或ActiveX的支持。
 缺点:只支持GET请求。

3. 使用HTML5 postMessage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

各浏览器兼容性如下:

一个简单的例子:

var popup = window.open('http://bbb.com', 'title');//父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法。
popup.postMessage('Hello World!', 'http://bbb.com');

postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。

父窗口和子窗口都可以通过message事件,监听对方的消息。message事件的事件对象event,提供以下三个属性:

  • 1、event.source:发送消息的窗口。
  • 2、event.origin: 消息发向的网址。
  • 3、event.data:消息内容。
 var onmessage = function (event) {  
   var data = event.data;//消息  
   var origin = event.origin;//消息来源地址  
   var source = event.source;//源Window对象  
   if(origin == "http://www.aaa.com"){  
    console.log(data);//hello world!  
   }  
    source.postMessage('Nice to see you!', '*');
 };  
 if (typeof window.addEventListener != 'undefined') {  
   window.addEventListener('message', onmessage, false);  
 } else if (typeof window.attachEvent != 'undefined') {  
   //ie  
   window.attachEvent('onmessage', onmessage);  
 }

4. 通过CORS跨域

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。所有浏览器都支持该功能,IE浏览器不能低于IE10

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

具体信息可以看下这篇博客:http://www.ruanyifeng.com/blog/2016/04/cors.html

原文地址:https://www.cnblogs.com/hankuikui/p/7049151.html