跨域--什么是跨域?以及跨域的常用解决方案
我们通常所说的跨域,就是指被同源策略限制了的请求场景。
什么是同源策略?
同源策略/SOP(Same origin policy)是一种约定,所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
常用解决方案
jsonp
通过动态生成script,设置src为请求的跨域地址,并在其中拼接回调函数。跨域地址收到请求后,返回一个对该回调函数的调用。从而达到数据通信的实现。
缺点:只支持get请求。
CORS
对于普通请求,只需服务端设置Access-Control-Allow-Origin即可;如果需要携带cookie,则前端需要设置withCredentials
postMessage
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递
语法: otherWindow.postMessage(message, targetOrigin, [transfer]);
message
: 传输的数据等
otherWindow
: 一个目标窗口的引用
a.) 通过window.open()返回值
b.) 通过iframe的contentWindow属性
targetOrigin
: 用来标识哪些窗口可以接受到消息。可以通过'*'配置为任何窗口。但为了安全性考虑,最好进行精准设置一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
transfer
: 是一串和message一起传递的数据,但是所有权会转到目标窗口。
用法如下:
var bWindow = window.open(...b details...)
var data = {name : 'ashen' ,age : 20}
bWindow.postMessage(data, 'http://b.org')
在bWindow中
window.addEventListener('message', receiveMessage, false)
function receiveMessage(event)
{
// 我们能信任信息来源吗?
if (event.origin !== "http://example.com:8080")
return;
// event.source 就当前的来源页面
// event.data 是 "{name : 'ashen' ,age : 20}"
// 假设你已经验证了所受到信息的origin (任何时候你都应该这样做), 一个很方便的方式就是把event.source
// 作为回信的对象,并且把event.origin作为targetOrigin
event.source.postMessage("hi there yourself! the secret response " +
"is: rheeeeet!",
event.origin);
}
nginx代理
配置代理服务器,在前端看来并非跨域
主要通过设置proxy_pass属性,为跨域地址
WebSocket协议跨域
websocket实现客户端和服务端的全双工通信,支持跨域
document.domain + iframe跨域
通过window.domain设置页面的基础主域相同
只能处理主域相同子域不同的情况
location.hash + iframe
例如需要实现A域的a.html到B域的b.html的跨域。则需要借助同为A域的c.html页面。利用hash值可单向传递的特性实现,如下:
// a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
setTimeout(function(){
iframe.src = iframe.src + '#user=admin'
}, 1000)
function onCallback(res){
alert('data from c.html ---->' + res)
}
</script>
<iframe src="http://www.domain1.com/c.html" style="display: none;"></iframe>
<script>
window.onhashchange = function(){
iframe.src = iframe.src + location.hash
}
</script>
<iframe src="http://www.domain2.com/c.html" style="display: none"></iframe>
<script>
window.onhashchange = function () {
window.parent.parent.onCallback(
"hello" + location.hash.replace("#user=", "")
);
};
</script>