跨域
同源策略
首先从同源策略开始讲
----何谓同源:相同的域名、相同的协议、相同的端口即为同源,若有其一不同则视为不同域。
----同源策略带来的限制:
1.cookie、localstorage、indexDB无法读取
2.DOM和JS对象无法读取
3.AJAX请求无法发送;
有时需要跨域请求资源,那么对于这一需求,有什么办法解决同源策略的限制呢?
1. jsonp(jsonp with padding)
jsonp和json的区别:
----json返回的的是一串数据;jsonp返回的是脚本代码
----jsonp只能用get请求,不能用post请求
在JS中,XMLHttpRequest对象无法直接请求跨域的资源,但是在页面上引入不同域上的JS脚本文件是可以的。jsonp利用该特性,具体实现思路是:在页面添加一个script标签 ,利用SRC属性获取对指定地址的请求,这点就类似是get请求。该请求会返回一个JS文件,文件载入成功后会执行在src的URL中指定的函数,并且会把需要的json数据作为参数传入。
<script>
function doSomething(jsonData) {
...................
}
</script>
<script src="http://example.com/data.php?callback=doSomething"></script>
利用jQuery实现jsonp
jQuery会自动生成一个全局函数替换callback=?中的问号,在获取到数据后会自动销毁。而$.getJSON方法会自动判断是否跨域,不跨域就会调用普通的ajax方法;若是跨域会以异步加载JS文件的形式来调用jsonp的回调函数。
<script>
$.getJSON('http://example.com/data/php?callback=?',function(jsondata){
//处理获得的数据
})
具有src属性的标签都可以实现跨域
2. CORS(cross-origin resource sharing)
cors分为简单请求和非简单请求
简单请求满足的条件:
---- 使用特定的请求方式如head、get、post
----并且请求头信息为:accept、accept-language、content-language、last-event-ID、content-type
普通跨域请求:服务器设置Access-Control-Allow-Origin即可。
带cookie请求的:前后端都要设置字段。
特点:
—cors支持所有类型的http请求,大多数浏览器支持cors除了IE6、IE7
—可以使用普通的XMLHttpRequest发起请求和获得数据,比jsonp有更好的错误处理
实现的思路:使用自定义的http头部,服务器根据浏览器的origin值来决定是否同意此次请求。
浏览器请求头:Origin: http://foo.example
服务器响应: Access-Control-Allow-Origin: http://foo.example[*] //表明可以被来自http://foo.example的域访问[若为*,表示可以被任意外域访问]
简单请求是使用特定的方式请求数据;非简单请求使用设定的方式请求数据之前先发送一个options请求,试探服务器是否允许客户端发送非简单请求,预检通过后会再一次发送请求用于数据传输,如下图:
详细介绍:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
3. document.domain+iframe
跨域一般分为:一种xhr不能访问不同源的文档,一种是不同的window之间是不可以进行交互操作的如页面中嵌入的iframe。
document.domain解决的是不同window之间不可以交互操作的情况。
案例:现在有一个页面A,地址是http://example.com/a.html,在该A页面中有一个 iframe,它的src是B页面的地址http://example.com/b.html,A页面与iframe是不同域的,所以现在带来的问题是无法在A页面中书写JS代码获取iframe中的内容:
A页面
<script>
function test() {
var iframe = document.getElementById('iframe');
var win = document.contentWindow;
var doc = win.document; //获取不到
var name = win.name; //获取不到
}
</script>
<iframe id="iframe" src="http://example.com/b.html" "text()"></frame>
解决办法:在A页面的http://example.com/a.html和http://example.com/b.html的document.domain都设为相同的域名即可。如下:
A页面
<script>
document.domain=‘example.com’; //设为主域!!!!
function test() {
//可以打印出
console.log(document.getElementById('iframe').contentWindow);
}
</script>
<iframe id="iframe" src="http://example.com/b.html" "text()"></frame>
B页面
<script>
document.domain="example.com"; // iframe载入的B页面的JS中也设置domain
function testB() {
}
</script>
注意:document.domain 的设置是有限制的,只能将domain设置为自身或者更高一级的父域,并且主域要相同,如上述的example.com是主域,如果设置为baidu.com则主域就不相同了。
4. window. name+iframe
window对象有个name属性,name属性的特征是在一个窗口的生命周期内,窗口载入的所有的页面会共享一个 window.name,每个页面都可以对window.name进行读写。
特点:兼容所有的浏览器; window中所有的页面都可以进行修改;window.name的值只可以是字符串的形式,最大是2M的容量。
A页面
<script>
window.name="我是A页面设置的值";
setTimeout(function() {
window.location="b.html"
},3000);
</script>
B页面
<script>
alert(window.name);
</script>
如何实现跨域?假设现在A页面是 www. example. com/a.html。需要利用A页面中的JS获取不同域的B页面 www. csdn. com/b.html中的window. name的值。
b.html代码如下:
<script>
window.name="我是A想要的数据";
</script>
要实现在A页面中不跳转获取到B页面的数据的解决办法:1.在A页面中嵌入iframe。利用iframe获取b.html的数据,然后A再从iframe中获取到想要的数据。
2. iframe要获取到 b.html的数据需要将 iframe标签的 src设置为B页面的地址 www. csdn. com/b.html。3. 需要再将 iframe的src属性设为与A页面同一个域的页面地址( 因为页面中嵌入的iframe和该页面不属于同源)。4. 然后在A页面的 JS代码里处理从B页面获取的数据,处理数据的代码完毕。
A页面代码如下:
A页面
<script>
var state = 0;//设置标志位来进行iframe与A页面同源的操作。
function getData(){
var iframe = document.getElementById('proxy');
iframe.onload = function() {
if(state===0){
iframe.src = "http://www.example.com/proxy.html"; //与A页面同源的某个代理页面,内容可以为空
state = 1;
}else if(state===1){
var data = iframe.contentWindow.name; //利用iframe的window.name获取B页面中设置的数据
console.log(data); //打印出“我就是A想要的数据”
destroyIframe(); //调用函数销毁iframe
}
}
function destroyIframe() {
iframe.contentWindow.close(); //处理完毕后最好关闭iframe,释放内存
iframe.contentWindow.close();
document.body.removeChild(iframe);
}
}
<body>
<iframe id='proxy' src="http://csdn.com/b.html" style="display:none" "getData()"></iframe>
</body>
proxy.html页面:
proxy.html 代理页
内容可以为空
- window.postMessage
HTML5引入的新特性,用于:页面和新打开的窗口的数据传递;多窗口之间消息传递;页面与嵌入的iframe消息传递。
用法:window.postMessage(data,origin)
data:传递的数据,最好用JSON.stringify()进行序列化,部分浏览器只支持字符串。
origin:协议+主机(http默认为www)+端口或者设置为*表示传递给任意窗口;如指定与当前窗口同源设置“/”。
A页面www.domain2.com/a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'aym'
};
// 向domain2传送跨域数据!!!!
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
};
B页面www.domain2.com/b.html
<script>
// 接收domain1的数据
window.addEventListener('message', function(e) {
alert('data from domain1 ---> ' + e.data);
var data = JSON.parse(e.data);
if (data) {
data.number = 16;
// 处理后再发回domain1
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
}
}, false);
</script>
参考资料:
https://blog.csdn.net/tjcjava/article/details/76468225
https://www.cnblogs.com/2050/p/3191744.html
前端常见跨域解决方案(全)http://www.cnblogs.com/roam/p/7520433.html