跨域的限制
- 无法获取
cookie、localStorage、indexDB - 无法获得
DOM - 无法发送
Ajax
关于cookie
共享cookie
cookie,是服务器端写入浏览器端的小段信息,只有同源的网页才能共享cookie,一级域名相同但二级域名不同的网页只要设置相同的document.domain,就可以共享cookie
补充知识点:
- 一级域名
qq.com - 二级域名
game.qq.com、www.qq.com、lol.qq.com - 三级域名
lpl.lol.qq.com
上述一段描述来自网上的文章,在此经过测试,提出了部分意见,关于意见是什么,后面会提到,现在先证明上述描述的不精确性。
验证的服务器nginx配置:
server {
listen 8080;
server_name w1.gaopeng.com;
location / {
root /Users/gaopeng/Sites/w1.gaopeng.com;
index index.html index.htm;
}
}
server {
listen 8080;
server_name w2.gaopeng.com;
location / {
root /Users/gaopeng/Sites/w2.gaopeng.com;
index index.html index.htm;
}
}
在w1.gaopeng.com、w2.gaopeng.com文件夹下的index.html内容
<script>
document.domain = "gaopeng.com";
</script>
主要目的是设置相同的document.cookie
浏览器打开w1.gaopeng.com,发现document.domain已经被设置gaopeng.com,此时增加一个cookie

w2.gaopeng.com
发现document.domain已经被设置gaopeng.com,但依旧无法获取上述设置的cookie:gao=peng

此时我们看下cookie存在的表现:

w1.gaopeng.com设置的cookie的Domain=w1.gaopeng.com

w2.gaopeng.com依然没有上述设置的cookie
突然想了一下如果将cookie设置为二级域名会怎么样呢?
在w1.gaopeng.com下,设置cookie

w2.gaopeng.com下,会获取到刚刚设置的cookie

再次观察w1.gaopeng.com、w2.gaopeng.com的cookie


因此得出了结论,cookie的共享与网站的是否同源并无明显的关系,能否共享应该看cookie自身的domain,如果domain相同,就可以共享
猜想:存在两个站点不同源(协议、端口不同)
A站:https://www.example.com:3443/
B站:http://www.example.com:3445/
由于cookie的domain都是www.example.com,那么这两个页面的cookie是可以共享的
关于获取DOM
iframe和window.open
只有同源的网页才能获取DOM,一级域名相同但二级域名不同的网页只要设置相同的
document.domain,就获取DOM
// w1.gaopeng.com/index.html
index01.html
<iframe id="myIFrame" src="http://w2.gaopeng.com:8080/"></iframe>
<script>
// document.domain = 'gaopeng.com';
// 如果去掉注释就可以获取到DOM
</script>
// w2.gaopeng.com/index.html
index02.html
<script>
document.domain = "gaopeng.com";
</script>

通过window.open的实例:

LocalStorage、IndexDB
利用上述方式的document.domain等特性都无法满足他们的通信,可以使用下面的介绍的通信,方式,在文章最后会介绍localStorage进行完全不同源的网站之间的通信。
非AJAX并且完全不同源的网站通信
完全不同源的nginx配置
server {
listen 8080;
server_name w2.gaopeng.com;
location / {
root /Users/gaopeng/Sites/w2.gaopeng.com;
index index.html index.htm;
}
}
server {
listen 8092;
server_name w2.gaopeng1.com;
location / {
root /Users/gaopeng/Sites/w2.gaopeng1.com;
index index.html index.htm;
}
}
在这里由于iframe与window.open的机理类似,所以只进行某一个种方式的演示
片段标识符(iframe)
片段标识符是指URL后面的#号部分,如果只是改变片段标识符,页面不会重新刷新。
父窗口可以把信息,写入子窗口的片段标识符。
// w2.gaopeng1.com/index.html
index02.html
<button id='button'>改变hash</button>
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
var srcUrl = "http://w2.gaopeng1.com:8092/#" + "gao=peng"
document.getElementById('button').onclick = function () {
document.getElementById('myIFrame').src = srcUrl;
}
</script>
// w2.gaopeng1.com/index.html
demo03.html
<script>
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
console.log('message', message);
}
</script>
如图所示,当点击改变hash按钮时,iframe页面会检测到hash的变化执行checkMessage方法

window.name(iframe)
浏览器窗口有一个window.name,这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置了这个属性,后一个网页可以读取它。
// w2.gaopeng1.com/index.html
index02.html
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
console.log(window.name);
</script>
// w2.gaopeng1.com/index.html
demo03.html
<script>
window.name = "gao=peng";
</script>
如图所示,主窗口活动了子窗口设置的window.name

window.postMessage(window.open)
上述的两种方法都是投机取巧的方式,在HTML5中正式引入了:跨文档通信 API
// w2.gaopeng1.com/index.html
index02.html
<iframe id="myIFrame" src="http://w2.gaopeng1.com:8092/"></iframe>
<script>
// 获取子窗口的引用
var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://w2.gaopeng1.com:8092/');
</script>
// w2.gaopeng1.com/index.html
demo03.html
<script>
window.onmessage = function(e) {
if (e.origin !== 'http://w2.gaopeng1.com:8092/') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
// 获取父窗口的引用
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, 'http://w2.gaopeng.com:8080/');
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
};
</script>
AJAX的跨域通信
解决方案:
- JSONP
- WebSocket
- CORS
主要谈论一下CORS对cookie的影响


ajax会自动带上同源的cookie,不会带上不同源的cookie- 可以通过前端设置
withCredentials为true, 后端设置Header的方式来让ajax自动带上不同源的cookie,但是这个属性对同源请求没有任何影响 - 如果
ajax请求设置withCredentials为true,注意:Access-Control-Allow-Origin必须制定特定的URL,不能是*, 且需要加上Access-Control-Allow-Credentials前端代码:
// 客户端也需要设置credentials: "include",不然服务端设置的cookie,也发送不过来
fetch("http://localhost:3000/post_form3", { method: "post", body: formData, credentials: "include" }).then(function(response) {
return response.json();
}).then(function(data) {
console.log(data);
}).catch(function(e) {
console.log(e);
});
后端代码
app.all('*', function(req, res, next) {
// 如果想让cookie发送至前端,必须设置为localhost:4000,而不是*
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Max-Age", 60); // 预检请求的有效期
res.header("Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods","PUT, POST, GET, DELETE, OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
关于上述代码中res.header("Access-Control-Max-Age", 60); // 预检请求的有效期,预检请求可以参考这篇文章