0
点赞
收藏
分享

微信扫一扫

JS 跨域详解


文章目录

  • ​​跨域与同源​​
  • ​​跨域​​
  • ​​同源策略​​
  • ​​不存在跨域的情况(无视同源策略)​​
  • ​​跨域常见的几种方法​​
  • ​​1. jsonp 跨域​​
  • ​​2. document.domain + iframe 跨域​​
  • ​​3. postMessage跨域​​
  • ​​4. CORS 跨域资源共享​​
  • ​​5. node代理跨域​​

跨域与同源

跨域

跨域是指从一个域名的网页去请求另一个域名的资源。比如从 ​​www.baidu.com​​​ 页面去请求 ​​www.google.com​​​ 的资源。
非同源,在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制

同源策略

同源策略是浏览器最核心也最基本的安全功能。如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

  • 同源:协议、域名、端口,三者全部相同,才是同源。
  • 跨域:协议、域名、端口,只要有一个的不同,就是跨域。

​http://www.123.com/index.html​​​ 调用 ​​http://www.123.com/server.php​​​ (非跨域)
​​​http://www.123.com/index.html​​​ 调用 ​​http://www.456.com/server.php​​​ (主域名不同:123/456,跨域)
​​​http://abc.123.com/index.html​​​ 调用 ​​http://def.123.com/server.php​​​ (子域名不同:abc/def,跨域)
​​​http://www.123.com:8080/index.html​​​ 调用 ​​http://www.123.com:8081/server.php​​​ (端口不同:8080/8081,跨域)
​​​http://www.123.com/index.html​​​ 调用 ​​https://www.123.com/server.php​​​ (协议不同:http/https,跨域)
请注意:​​​localhost​​​ 和 ​​127.0.0.1​​ 虽然都指向本机,但也属于跨域。

不存在跨域的情况(无视同源策略)

  1. 服务端请求服务端不存在跨域(浏览器请求服务器才存在同源策略)
  2. ​<img src="跨域的图片地址">​​​ (​​<img>​​​标签的​​src​​ 属性不存在跨域)
  3. ​<link href="跨域的css地址">​​​ (​​<link>​​​标签的​​href​​ 属性不存在跨域)
  4. ​<script src="跨域的js地址"></script>​​​ (​​<script>​​​标签的​​src​​ 属性不存在跨域)

跨域常见的几种方法

1. jsonp 跨域

jsonp是一种跨域通信的手段,它的原理其实很简单:

利用​<script>​标签的src属性跨域

由于使用script标签的src属性,因此​​只支持get方法​

function jsonp(req){
// 动态创建script标签
var script = document.createElement('script');
var url = req.url + '?callback=' + req.callback.name;
script.src = url;
document.getElementsByTagName('head')[0].appendChild(script);
}

// 调用
jsonp({
url : '',
callback : hello
});

当然,jquery也支持jsonp的实现方式:

$.ajax({
url:'http://www.xxx.com',
type:'GET',
dataType:'jsonp',// 请求方式为jsonp
jsonpCallback:'callback',
data:{
"username":"xxx"
}
})

2. document.domain + iframe 跨域

​两个域名必须属于同一个主域名!​​而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域。

什么是主域名相同呢?

  • www.baidu.com(百度官网)
  • map.baidu.com(百度地图)
  • tieba.baidu.com(百度贴吧)
  • news.baidu.com(百度新闻)
  • image.baidu.com(百度图片)

这五个主域名都是​​baidu.com​

.

举个例子,现在有两个页面:

  1. news.baidu.com(news.html)
  2. map.baidu.com(map.html)

news.baidu.com里的一个网页(news.html)引入了map.baidu.com里的一个网页(map.html)

这时news.html里同样是不能操作map.html里面的内容的。
因为document.domain不一样,一个是news.baidu.com,另一个是map.baidu.com。
这时我们就可以通过Javascript,​​​将两个页面的domain改成一样的​​​,
需要在a.html里与b.html里都加入:

document.domain = “baidu.com”;

这样这两个页面就可以互相操作了。也就是实现了同一一级域名之间的"跨域"。

具体代码:

<!-- news.baidu.com下的news.html页面 -->
<script>.domain = 'baidu.com';
var ifr = document.createElement('iframe');
ifr.src = 'map.baidu.com/map.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 这里可以跨域操作map.baidu.com下的map.html页面
var oUl = doc.getElementById('ul1');
alert(oUl.innerHTML);
ifr.onload = null;
};</script>

<!-- map.baidu.com下的map.html页面 -->
<ul id="ul1">我是map.baidu.com中的ul</ul>
<script>.domain = 'baidu.com';</script>

3. postMessage跨域

在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging)
Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage

postMessage可以解决:

  • 页面和其打开的新窗口的数据传递
  • 多窗口之间消息传递
  • 页面与嵌套的iframe消息传递
  • 上面三个场景的跨域数据传递

postMessage(data,origin)方法接受两个参数:

  • data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
  • origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

.

举个栗子
a.html (www.baidu.com/a.html)

<iframe id="iframe" src="http://www.qq.com/b.html" style="display:none;"></iframe>
<script>var iframe = document.getElementById('iframe');
iframe.onload = function() {
var data = {
name: 'xxx'
};
// 向qq.com传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.qq.com');
};

// 接受由qq.com返回数据
window.addEventListener('message', function(e) {
alert('data from qq ---> ' + e.data);
}, false);</script>

b.html (www.qq.com/b.html)

<script>// 接收由baidu.com返回的数据
window.addEventListener('message', function(e) {
alert('data from baidu ---> ' + e.data);

var data = JSON.parse(e.data);
if (data) {
data.number = 16;
// 处理后再发回baidu.com
window.parent.postMessage(JSON.stringify(data), 'http://www.baidu.com');
}
}, false);</script>

4. CORS 跨域资源共享

是目前主流的跨域解决方案

​​CORS 跨域资源共享传送门​​

5. node代理跨域

​跨域行为是浏览器禁止的,但是服务端并不禁止。​​使用proxyTable的原理就是将域名发送给本地的node服务器,再由本地的服务器去请求真正的服务器。

以vue为例

config/index.js文件中

proxyTable: {
'/api': {
// 测试环境
target: 'http://baidu.com', // 接口域名 要代理的url
changeOrigin: true, //是否跨域
pathRewrite: {
'^/api': ''
}
}

配置完必须要重启node服务才会生效!!!


举报

相关推荐

0 条评论