跨域请求

来源:互联网 发布:linux 定时器 编辑:程序博客网 时间:2024/06/06 01:24

1、jsonp(动态创建script标签)

<script>     var _script = document.createElement('script');     _script.type = "text/javascript";     _script.src = "http://localhost:8888/jsonp?callback=f";     document.head.appendChild(_script);</script>

浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行。实际项目中JSONP通常用来获取json格式数据,这时前后端通常约定一个参数callback,该参数的值,就是处理返回数据的函数名称。

缺点:只能发送get方式的请求

2、Proxy代理(首先将请求发送给后台服务器,通过服务器来发送请求)

这里写图片描述

代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证
书)或者忽略证书检查,否则你的请求无法成功。

3、CORS

这里写图片描述

当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

4、通过document.domain跨域

不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。比如,有一个页面,它的地址是http://www.damonare.cn/a.html , 在这个页面里面有一个iframe,它的src是http://damonare.cn/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:

<script type="text/javascript">    function test(){        var iframe = document.getElementById('ifame');        var win = document.contentWindow;//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的        var doc = win.document;//这里获取不到iframe里的document对象        var name = win.name;//这里同样获取不到window对象的name属性    }</script><iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe>

这个时候,document.domain就可以派上用场了,我们只要把http://www.damonare.cn/a.html和http://damonare.cn/b.html这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。
在页面http://www.damonare.cn/a.html 中设置
document.domain:

<iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe><script type="text/javascript">    document.domain = 'damonare.cn';//设置成主域    function test(){        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象    }</script>

在页面http://damonare.cn/b.html 中也设置document.domain:

document.domain = 'damonare.cn';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同

修改document.domain的方法只适用于不同子域的框架间的交互。

5、通过HTML5的postMessage方法跨域

高级浏览器Internet Explorer 8+, chrome,Firefox , Opera 和 Safari 都将支持这个功能。这个功能主要包括接受信息的”message”事件和发送消息的”postMessage”方法。比如damonare.cn域的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页面监听并接受消息。

6、通过window.name跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

比如:我们在任意一个页面输入window.name = "My window's name";setTimeout(function(){    window.location.href = "http://damonare.cn/";},1000)

进入damonare.cn页面后我们再检测再检测 window.name :

window.name; // My window’s name

可以看到,如果在一个标签里面跳转网页的话,我们的 window.name 是不会改变的。
基于这个思想,我们可以在某个页面设置好 window.name 的值,然后跳转到另外一个页面。在这个页面中就可以获取到我们刚刚设置的 window.name 了。

由于安全原因,浏览器始终会保持 window.name 是string 类型。
同样这个方法也可以应用到和iframe的交互来:

比如:我的页面(http://damonare.cn/index.html)中内嵌了一个iframe:

<iframe id="iframe" src="http://www.google.com/iframe.html"></iframe>

在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:

var iframe = document.getElementById('iframe');var data = '';iframe.onload = function() {    data = iframe.contentWindow.name;};Boom!报错!肯定的,因为两个页面不同源嘛,想要解决这个问题可以这样干:var iframe = document.getElementById('iframe');var data = '';iframe.onload = function() {    iframe.onload = function(){        data = iframe.contentWindow.name;    }    iframe.src = 'about:blank';};

或者将里面的 about:blank 替换成某个同源页面(about:blank,javascript: 和 data: 中的内容,继承了载入他们的页面的源。)

这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。

原创粉丝点击