javascript 跨域

跨域:协议、域名、端口 任何一项不同即为跨域.

一般 js 涉及到的跨域场景包括: ajax 请求的跨域、 cookie 跨域共享(子域名跨域)、iframe 与 parant 的 window 之间的消息传送。

1、jsonp 不受跨域限制,需要目标服务器配合输出指定 js 代码。

2、域名不同,但主域名相同的窗口,可以修改 document.domain = "主域名" 来实现同源(同理,还有 cookies 的共享设置也是通过这种方法),这种方法可以使一级 XMLHttpRequest 实现通讯。

3、websocket 将 http 协议升级为 ws 协议。

4、二级 XMLHttpRequest 跨域: 服务器返回响应头 Access-Control-Allow-Origin:请求方域名,浏览器发往服务器的 origin 请求头包含了请求方域名,这是由浏览器的 XMLHttpRequest  对象自动发送的,并且不能修改。 IE8+ 可以使用 XDomainRequest 。

// XMLHttpRequest level2
var params = 'a=1&b=2';
var method = 'post';
var url = 'http://www.api.com/xcross.php';
var async = true;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
    if(this.readyState==4&&this.status==200){
        console.log(this.responseText);
    }
}
xhr.open(method, url, async); 
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //post 普通字符串参数
xhr.setRequestHeader("X-Requested-With","XMLHttpRequest"); 
xhr.setRequestHeader("Myheard","this is a request header of contract"); xhr.send(params);
//XMLHttpRequest level2 的服务器响应 php

//可将允许跨域请求的域名设置为 * ,表示不限制请求来源
header('Access-Control-Allow-Origin:http://localhost'); 

/*
允许浏览器发来的 request 头信息,尤其是想要自定义头信息时应该在这里约定,否则请求会被禁止
比如允许浏览器发送一个名为 Myheard 的自定义 请求头.
最好设置一下 Content-Type ,
浏览器使用 xhr 的 post 方式进行求 ajax 请求时,
可能会默认发送 content-type:application/xml (chrome浏览器),这可能不被服务器接受(取决于服务器默认配置参数),
而且 post 普通字符串参数时不应该 使用 application/xml,应该在 js 设置 Content-Type:application/x-www-form-urlencoded X-Requested-With 请求头可用于判断浏览器端请求方式
*/ header('Access-Control-Allow-Headers:Origin, Content-Type, X-Requested-With, Accept, Myheard'); //输出数据 echo json_encode(array('x'=>123,'y'=>456));

  

5、 iframe 窗口与父窗口在跨域情况下,可以互相获取 window 对象(iframeNode.contentWindow、 window.parent),但不能访问 window 对象的属性,topWindow 不能获取 iframe 中 的 iframe window 对象(因为无法获取 iframe 中的 iframeNode),反之却可以 (window.parent.parent)。

6、window.name 属性在 location.href 被修改后仍然保留,parent 中修改 iframe 的 src 为同域名后可以访问 iframe 的 window.name 。

7、iframe 窗口在跨域情况下虽然不能访问 window 的属性值,却可以修改 window.location.href,修改 location.href 的锚点不会发起请求,甚至在访问跨域的子窗口也被禁止的情况下,location.href 的修改也能成功,比如一个跨域的 iframe 内修改父页面中的另一个跨域的 iframe 的地址: 

//由于 iframe 跨域,访问父页面的 frames 其实是被禁止的,但是设置 location.href 可以成功
parent.frames['otheIframe'].location.href = "http://www.cnblogs.com/ecalf/"; 

 8、IE 6、7下,跨域的 iframe window 可以共享 window.navigator,可以通过自定义 window.navigator 上的属性来达到跨域,这种跨域方式可以直接传 js 对象型数据。

9、window.postMessage:适用于IE8+,FF,Chrome,opera 等较新的浏览器。

获取 window 对象(包括 iframeNode.contentWindow、window.open 创建的窗口,当然也可以蛋痛地向本窗口 postMessage )后使用 HTML5 的window.postMessage 方法, iframeNode.contentWindow.postMessage("msg"," * 或 contentWindow中的域名") ,在 iframe 中使用 window.onmessage 事件实现跨域消传送,注意,iframe 在加载完毕后,父窗口 的 onload 事件才触发,不要在 onload 事件之前( iframe 加载完毕前)就 postMessage。

<iframe id="xx1" src="http://localhost/test/2.html"></iframe>
<script>
console.log('hello world');
window.onload = function(){
    var win = document.getElementById('xx1').contentWindow;
    win.postMessage('post message:hello world','http://localhost');        
};
</script>
//http://localhost/test/2.html  接收 postMessage 的消息
function receiveMessage(e){
    console.log(e);
    alert(e.data+',from:'+e.origin);
}
window.addEventListener("message", receiveMessage, false);

10、window.name 和 location.hash 存储的信息比较少,不适用单次的大数量传输,window.name 没有消息送达的提示方式,靠定时轮询检测,IE 6/7 没有 onhashchange 事件(该事件绑定在 window 或 body 上,IE8+ 和其他较新的浏览器支持该事件),也靠定时检测。

11、借助 flash 和 在 server 发送的跨 域请求(本方服务器转发,或者要求跨域服务器处理请求后跳转到本方指定URL,比如使用js  post 一个表单到跨域服务器,对方处理后转跳到本方服务器的URL),这已超出 javascript 范畴,3、4、9 方法不适用于古董级浏览器,对于 window 属性的读取限制多发生在 比较新的浏览 器(比如 opera),一般这些浏览器都支持 postMessage,可以通过检测手段优先使用 postMessage

 综上总结可以看到:跨主域的通讯总是需要对方服务器配合(输出指定的js代码:比如postMessage ,jsonp,页面跳转,或信息头:Access-Control-Allow-Origin,或提供中转用的页面)支持才能实现,ie 6 7 的 navigator 是个BUG 例外。

关于cookie 的javascript 访问禁止及 跨域时的“第三方 cookie” 参考下面连接:

http://hi.baidu.com/ecalf830/item/00d142d8b66a38e2795daa48

原文地址:https://www.cnblogs.com/ecalf/p/2786368.html