同源政策是指如果两个网站不同源。则两网站不能访问对方的:
1.cookie,IndexDB,LocalStorage
2.Dom节点
3.Ajax请求不能发送
-
那同源需要满足什么呢?
协议相同
域名相同
端口相同
-
首先我们先来说说常用的ajax跨域需求
JSONP(JSONP只能发送get请求)
JSONP是客户端与服务端跨域通信的常用方法,简单实用,兼容老式浏览器 1.网页动态插入script标签 function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); }; 2.服务器收到这个请求后,会将数据放在回调函数的参数位置返回: foo({ "ip": "8.8.8.8" });
WebSocket
WebSocket支持不同源政策
-
Cookie
Cookie是服务器写入浏览器的信息,必须是同源网页才能共享。不过一级域名相同,二级域名不同,允许通过设置document.domain共享Cookie。
两个页面都设置document.domain = 'liuwen.com';
其中一个页面设置 document.cookie = 'name = louden'
另一个页面读这个cookie:var allCookie = document.cookie;
iframe
如果两个网页不同源,就无法拿到对方的DOM,典型的例子就是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。父窗口获取子窗口:
document.getElementById("myIFrame").contentWindow.document
子窗口获取父窗口:
window.parent.document.body
如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain即可。
如果是完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。
- 片段标示符
- window.name
- 跨文档通信API
片段标示符
片段标示符是URL的#后面的部分,比如
http://163.com/a.html#fragment的#fragment,如果只是改变片段标示符,页面不会重新刷新。
父窗口可以把信息,写入子窗口的片段标示符:
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
子窗口可以通过监听hashchange事件得到通知:
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
// ...
}
同样的,子窗口也可以改变父窗口的片段标示符:
parent.location.href= target + "#" + hash;
window.name
浏览器窗口有window.name属性,这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个页面设置了这个属性,后一个网页可以读取它。
父窗口先打开一个子窗口,载入一个不同源的页面,该网页将信息写入window.name属性:
window.name = data;
子窗口跳回一个与主窗口同域的网址:
location = 'http://parent.url.com/xx.html';
然后,主窗口就可以读取子窗口的window.name了:
var data = document.getElementById('myFrame').contentWindow.name;
优点是window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性值的变化,影响页面性能。
window.postMessage
HTML5的全新API:跨文档通信API。
父窗口
http://aaa.com
向子窗口http://bbb.com
发消息,调用postMessage方法就可以了:
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
posetMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即”协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法类似:
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父窗口和子窗口都可以通过message事件,监听对方的消息:
window.addEventListener('message', function(e) {
console.log(e.data);
},false);
message事件的事件对象event,提供以下三个属性:
- event.source:发送信息的窗口
- event.origin:信息发向的网址
- event.data:信息内容
下面可以看看几个例子:
子窗口通过event.source属性引用父窗口,然后发送信息:
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
event.source.postMessage('Nice to see you!', '*');
}
event.origin属性可以过滤不是发送本窗口的信息:
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
if (event.origin !== 'http://aaa.com') return;
if (event.data === 'Hello World') {
event.source.postMessage('Hello', event.origin);
} else {
console.log(event.data);
}
}