参考学习:https://blog.youkuaiyun.com/letterTiger/article/details/79520375
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
同源策略的限制:
1.存储在浏览器中的数据,如localStroage、Cooke和IndexedDB不能通过脚本跨域访问
2.不能通过脚本操作不同域下的DOM
3.不能通过ajax请求不同域的数据
跨域解决办法
1.document.domain
2.Hash iframe
3.window.name
4.window.postMessage
5.jsonp
6.CORS
7.websocket
疑问??
nginx代理跨域
nodejs中间件代理跨域
后端在头部信息里面设置安全域名
规避同源策略
1.cookie同源策略的规避:
document.domain
A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,那么只要设置相同的document.domain,两个网页就可以共享Cookie。
document.domain = 'example.com';
现在,A网页通过脚本设置一个 Cookie。
document.cookie = "test1=hello";
B网页就可以读到这个 Cookie。
var allCookie = document.cookie;
注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 无法通过这种方法,规避同源政策,而要使用下文介绍的PostMessage API。
2.DoM同源规避:
document.domain
Hash(片段识别符)
window.name
window.postMessage
3.Ajax同源策略规避:
jsonp
CORS
webSocket
如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。
比如,父窗口运行下面的命令,如果iframe窗口不是同源,就会报错。
document.getElementById("myIFrame").contentWindow.document
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.
上面命令中,父窗口想获取子窗口的DOM,因为跨源导致报错。
反之亦然,子窗口获取主窗口的DOM也会报错。
window.parent.document.body
// 报错
document.domain document.domain只可以在拥有相同的主域名的不同子域名之间跨域。两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享 Cookie。
hash因为hash的改变并不会引起页面的刷新同时可以通过 window.onhashchange事件监听到hash的改变,所以可以通过hash来跨域传递数据。
注意:该方法会直接暴露所传递的数据并且对所传数据有大小限制。
父窗口可以把信息,写入子窗口的片段标识符。
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
参考学习
https://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html
window.name有一个特性,即使当前窗口的地址改变了window.name的值也不会改变。可以利用这一特性来进行跨域,步骤如下:
1 .通过iframe加载需要获取数据的地址
2. 在加载的文件上将数据设置到window.name上
3. 数据获取完成后将iframe的地址设置为当前文档同域
4.通过DOM操作拿到window.name上的数据
window.postMessage(h5中新增跨文档通信API)
messageEvent对象上的属性中有三个属性要注意,分别是:
1.source 发送消息的窗体
2. origin 发送消息的域名 (根据域名判断是否处理该消息)
3.data 发送消息的内容 (获取发送的消息内容)
这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
举例来说,父窗口http://aaa.com向子窗口http://bbb.com发消息,调用postMessage方法就可以了。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法类似。
window.opener.postMessage('Nice to see you', 'http://aaa.com');
父窗口和子窗口都可以通过message事件,监听对方的消息。
window.addEventListener('message', function(e) {
console.log(e.data);
},false);
下面的例子是,子窗口通过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);
}
}
jsonp jsonp只支持GET请求。
网页通过添加一个script元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入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);
};
上面代码通过动态添加script元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。
服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。
foo({
"ip": "8.8.8.8"
});
由于<script元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。
后台程序的响应头加上如下字段:
Access-Control-Allow-Origin: http://example.com
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。