什么是跨域
当请求URL的协议、域名、端口号其中任意一个与当前页面url不同时,就是跨域。
为什么会发生跨域(同源策略)
浏览器具有同源策略,只有同源才能相互访问,不同源,则会发生跨域。
1、什么是同源?
同源就是同一个域,相同的协议、主机(域名)、端口号。
2、为什么要使用同源策略?
同源策略是浏览器最核心也是最基本的安全功能,它不允许一个域的js脚本与另一个域的脚本进行交互,有效防止XSS,CSRF等攻击。
3、同源策略造成的问题?
(1)无法读取不同源页面的cookie、localStorage和indexedDB(浏览器数据库)
(2)无法处理非同源的DOM元素与js对象
(3)无法向非同源页面发送ajax请求
跨域解决方案
1、document.domain+iframe
主域相同,子域不同,用js强制设置document.domain为基础主域,实现同域
例如:
父窗口: http://www.domain.com/a.html
子窗口:http://child.domain.com/b.html
在父页面中设置:
<script>
document.domain = "domain.com";
var user = "admin";
</script>
在子页面中设置:
<script>
document.domain = "domain.com";
console.log(window.parent.user); //'admin'
</script>
2、location.hash+ifame
3个页面,不同域名之间传递数据
例如:
a.html: http://www.domain1.com/a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
// 向b.html传hash值
setTimeout(function() {
iframe.src = iframe.src + '#user=admin';
}, 1000);
// 开放给同域c.html的回调方法
function onCallback(res) {
alert('data from c.html ---> ' + res);
}
</script>
b.html: http://www.domain2.com/b.html
<iframe id="iframe" src="http://www.domain1.com/c.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
// 监听a.html传来的hash值,再传给c.html
window.onhashchange = function () {
iframe.src = iframe.src + location.hash;
};
</script>
c.html: http://www.domain1.com/c.html
<script>
// 监听b.html传来的hash值
window.onhashchange = function () {
// 再通过操作同域a.html的js回调,将结果传回
window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=', ''));
};
</script>
3、window.name+iframe
通过iframe的src属性,由外域转向本地域,跨域数据由window.name传递到本地域。name值在不同域加载后依然存在,而且支持很长的值,2M。
例如:
a.html: http://www.domain1.com/a.html
b.html: http://www.domain2.com/b.html
a请求b里面的window.name="This is domain2 data!";
a页面方法:
function proxy(url, callback){
var state = 0;
var iframe=document.createElement('iframe');
iframe.src = url;
iframe.onload = function(){
if(state == 1){
callback(iframe.contentWindow.name);
//销毁
destoryFrame();
}else {
//切换到同域
iframe.contentWindow.location = "http://www.domain1.com/proxy.html";
state = 1;
}
}
document.body.append(iframe);
function destoryFrame(){
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
}
}
//请求数据
proxy("http://www.domain2.com/b.html", function(data){
alert(data);
})
proxy.html是中间代理页面,与a同域,为空即可。
4、postMessage
页面和其打开的新窗口的数据传递
多窗口之间的消息传递
页面与嵌套的iframe消息传递
上面三个场景的跨域数据传递
例如:
a.html:http://www.domain1.com/a.html
iframe.contentWindow.postMessage(data, "http://www.domain2.com/b.html")
window.addEventListener('message', function(e){
alert(e.data)
})
b.html:http://www.domain2.com/b.html
window.addEventListener('message', function(e){
dataB = 'test'
})
window.parent.postMessage(dataB, "http://www.domain1.com/a.html");
5、jsonp
通常为了减轻服务器压力,会把js、css、图片等静态资源放到另一台独立域名的服务器上,在html中通过相应的标签从不同域名下加载静态资源,这种方式是被浏览器允许的。
所以可以让服务端返回一段调用某个函数的代码,在src中进行调用,实现跨域。
只能使用GET请求方式;需要后台封装数据
例如:
//在页面中动态定义script标签,传入调用的远程js文件
<script src="./getData.js"></script>
//远程getData.js文件返回一个含有调用函数名的数据
getremotedata({
code:0,
result:'success'
});
//使用jQuery发起jsonp请求
<script type="text/javascript">
function GetAjaxData() {
$.ajax({
type: "get",
async: false,
url: "http://localhost:8080/getdata.php",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,标识jsonp回调函数名(一般为:callback)
jsonpCallback: "GetData", //callback的function名称
success: function (data) {
console.log(data);
},
error: function () {
alert('fail');
}
});
}
</script>
6、跨域资源共享CORS
需要服务端实现CORS接口
对于简单请求,浏览器在头信息中添加也给Origin字段,添加远程域名,服务器根据这个值判断是否同意请求
CORS参考文章:http://www.ruanyifeng.com/blog/2016/04/cors.html
7、nginx反向代理
8、nodejs中间件代理跨域
9、WebSocket协议跨域
参考文章: http://www.manongjc.com/detail/19-vgapwneyijiifjt.html