跨域知识点部分总结

跨域的限制

  • 无法获取cookielocalStorageindexDB
  • 无法获得DOM
  • 无法发送Ajax

关于cookie

共享cookie

cookie,是服务器端写入浏览器端的小段信息,只有同源的网页才能共享cookie一级域名相同但二级域名不同的网页只要设置相同的document.domain,就可以共享cookie

补充知识点:

  • 一级域名 qq.com
  • 二级域名 game.qq.comwww.qq.comlol.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.comw2.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,但依旧无法获取上述设置的 cookiegao=peng

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

我们发现在 w1.gaopeng.com设置的 cookieDomain=w1.gaopeng.com
发现 w2.gaopeng.com依然没有上述设置的 cookie


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

此时会发现在 w2.gaopeng.com下,会获取到刚刚设置的 cookie

再次观察w1.gaopeng.comw2.gaopeng.comcookie

发现第二次设置的cookie共享了

因此得出了结论,cookie的共享与网站的是否同源并无明显的关系,能否共享应该看cookie自身的domain,如果domain相同,就可以共享

猜想:存在两个站点不同源(协议、端口不同)

A站:https://www.example.com:3443/

B站:http://www.example.com:3445/

由于cookiedomain都是www.example.com,那么这两个页面的cookie是可以共享的

关于获取DOM

iframewindow.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;
    }
}
复制代码

在这里由于iframewindow.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

主要谈论一下CORScookie的影响

如上面两张图对比所示,当发起Ajax请求时:

  1. ajax会自动带上同源的cookie,不会带上不同源的cookie
  2. 可以通过前端设置withCredentialstrue, 后端设置Header的方式来让ajax自动带上不同源的cookie,但是这个属性对同源请求没有任何影响
  3. 如果ajax请求设置withCredentialstrue,注意: 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); // 预检请求的有效期,预检请求可以参考这篇文章

参考文章

浏览器同源政策及其规避方法

Ajax不会自动带上cookie

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值