本文参考自阮一峰老师的文章链接在此http://www.ruanyifeng.com/blog/2016/04/cors.html
一、简单介绍同源策略,即三个相同:
协议相同,域名相同,端口相同。
二、同源策略主要带来三个方面的行为限制:
1、cookie,localstorage和IndexDB无法读取
2、DOM无法获取
3、Ajax请求不能发送
三、规避方法
1、cookie的读取: 如果两个网页的一级域名一样,二级域名不同。此时可以通过设置document.domain来共享cookie,举个栗子:
A网页域名:https:\\a.example.com B网页域名:https:\\b.example.com
此时A、B网页js脚本同时设置document.domain = "example.com";
现在A页面设置cookie: docuemnt.cookie = "title=hello";
此时B页面就可以通过 document.cookie读取到A页面设置的cookie。
还可以在服务器设置cookie的时候指定cookie所属域名为一级域名,这样在二级、三级域名下就不用做任何设置就可以读取到这个cookie
注意事项:
1、这种方式只适用于一级域名相同
2、只适用于cookie和iframe,localstorage与IndexDB无法使用。
2、localstorage和IndexDB读取
通过H5的postMessage读写其他窗口的localstorage.举个例子
父窗口https://a.com 子窗口https://b.com
父窗口向子窗口发送消息:
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com');
子窗口写入父窗口的localStorage
window.onmessage = function(e){
if(e.orgin !== "https://b.com"){
return;
}
var data = JSON.parse(e.data);
localstorage.setItem(data.key,JSON.stringify(data.data));
}
3、DOM的获取
三种规避方法:1、片段识别符;2、window.name;3、window.postMessage
1、片段识别符
片段识别符值的是url的#后面的部分,这一部分的改变不会引起页面的刷新,但这一个变化可以通过window.onhaschange监听到。因此父窗口可以
把信息写到子窗口的片段标识符中。如:
父窗口发送信息
var src = orginURL + "#" + data;
document.getElementById("myIFrame").src = src;
子窗口接受信息
window.onhaschange = function(){
var message = window.location.hash;
}
同样地子窗口也可以改变父窗口片段标识符
2、window.name
window.name:不管是否同源,只要在同一个窗口,前一个网页设置了,后一个网页就可以读取到
父窗口先打开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。
window.name = data;
接着,子窗口跳回一个与主窗口同域的网址。
location = 'http://parent.url.com/xxx.html';
然后,主窗口就可以读取子窗口的window.name了。
var data = document.getElementById('myFrame').contentWindow.name;
这种方法的优点是,window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性的变化,影响网页性能。
3、postMessage
此方法可参考localstorag。
4、Ajax
1、jsop
基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回
客户端代码:
<script> function mycall(data){
console.log(data);
}
function addScriptTag(src) {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.src = src;
document.body.appendChild(script);
}
addScriptTag('http://127.0.0.1:3000/?callback=mycall');
</script>
服务器端为node.js代码:
app.get('/',function(req,res){
var callback = req.query.callback;
var data = 11;
res.send(callback+"("+data+")");
res.end();
});
2、websocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
下面是一个例子,浏览器发出的WebSocket请求的头信息。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。
正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
3、CORS
是解决ajax跨域的根本方法,具体请参考阮一峰老师的http://www.ruanyifeng.com/blog/2016/04/cors.html