function demo(){
console.log(data.msg)
}
前端程序员不可避免的会遇到跨域这个问题,而随着时间的推移,解决跨域问题的方法也是日渐丰富。于是我就稍作整理,来完善自己的知识体系,如恰好也能帮你解决一些问题,那我将非常高兴。
方法一:jsonp
假设,我们源页面是在a.com,想要获取b.com的数据,我们可以动态插入来源于b.com的脚本:
script = document.createElement('script');
script.type='text/javascript';
script.src = 'http://www.b.com/getdata?callback=demo'
这里,我们利用动态脚本的src属性变相的发送了一个http://www.b.com/getdata?callback=demo的GET请求。这个时候,b.com页面接收到这个请求时,如果没有JSONP,会正常返回json的数据结果,像这样:
{msg:‘helloworld’}
而利用JSONP,服务端会接受这个callback参数,然后利用这个参数包装要返回的数据:
这个时候,如果a.com的页面上敲好有demo的函数:
function demo(data){console.log(data.msg)};
当远程数据一返回的时候,随着动态脚本的执行,这个demo函数就会被执行。
方法二:$.getJSON
$.getJSON('http://www.b.com/getdata?callback=?',function(data){console.log(data.msg)})
方法三:$.ajax
这种方法,只要指定dataType为jsonp即可
$.ajax({
url:'http://www.b.com/getdata?callback=?',
dataType:'jsonp',
jsonpCallback:'demo',
success:function(data){
console.log(data.msg);
}
})
缺陷:1.没有关于JSONP调用的错误处理,一旦回调函数调用失败,浏览器会以静默失败的方式处理。
2.它只支持GET请求,这是该技术本身的特性所决定的。
方法四:document.domian
域名与子域名之间也同样受同源策略的限制,因此当域名与子域名需要通信时,我们可以如下操作:
document.domain ='a.com';
var iframe = document.createElement('iframe');
iframe.src = 'http://document.a.com';
iframe.style.display= "none";
document.body.appendChild(iframe);
iframe.onload = function(){
var targetDocument = iframe.contentDocument||iframe.contentWindow.document;
}
方法五:
window.name这个全局属性主要是用来获取和设置窗口名称的,但是通过结合iframe也可以跨域获取数据。我们知道,每个iframe都有包裹它的window对象,所以window。name属性就可以被共享。
例子:
var iframe = document.createElement('iframe');
var canGetData = false;
//监听事件
iframe.onload = function(){
if(!canGetData){
iframe.src = 'http://www.a.com';
canGetData = true;
}else{
var data = iframe.contentWindow.name;
//获取数据后取出iframe,防止不断刷新
iframe.contentWindow.close();
document.body.removeChild(iframe);
}
}
iframe.src = 'http://www.b.com/getdata.html'
iframe.style.display = 'none';
document.body.appendChild(iframe);
b.com/getdata.html中存放的数据需要存储在window。name属性中:
<script>
var data = {msg:'hello,world'};
window.name = JSON.stringify(data);
</script>
方法六:window.postMessage(重点推荐) 跨文档消息
用postMessage的特性可以实现为安全可信的跨域通信
postMessage是HTML5新增在window对象上的方法,目的是为了解决在父子页面上通信的问题。该技术有个专有名词:跨文档消息(cross-document messaging)。利用postMessage的特性可以实现较为安全可信的跨域通信。
postMessage方法接受两个参数:
message: 要传递的对象,只支持字符串信息,因此如果需要发送对象,可以使用JSON.stringify和JSON.parse做处理
targetOrigin: 目标域,需要注意的是协议,端口和主机名必须与要发送的消息的窗口一致。如果不想限定域,可以使用通配符“*”,但是从安全上考虑,不推荐这样做。
下面介绍一个例子:
首先,先创建一个demo的html文件,我们这里采用的是iframe的跨域,当然也可以跨窗口。
<p> <button id="sendMsg">sendMsg</button> </p>
<iframe id="receiveMsg" src="http://b.html"> </iframe>
然后,在sendMsg的按钮上绑定点击事件,触发postMessage方法来发送信息给iframe:
window.onload = function() { var receiveMsg = document.getElementById('receiveMsg').contentWindow;
//获取在iframe中显示的窗口
var sendBtn = document.getElementById('sendMsg');
sendBtn.addEventListener('click', function(e) {
e.preventDefault(); receiveMsg.postMessage('Hello world', 'http://b.html');
});
}
接着,你需要在iframe的绑定的页面源中监听message事件就能正常获取消息了。其中,MessageEvent对象有三个重要属性:data用于获取数据,source用于获取发送消息的窗口对象,origin用于获取发送消息的源。
window.onload = function() {
var messageBox = document.getElementById('messageBox');
window.addEventListener('message', function(e) {
//do something //考虑安全性,需要判断一下信息来源
if(e.origin !== 'http://xxxx') return;
messageBox.innerHTML = e.data;
});
}
总得来说,postMessage的使用十分简单,在处理一些和多页面通信、页面与iframe等消息通信的跨域问题时,有着很好的适用性。
七:服务器跨域
八:CORS(跨域资源共享)