「JavaScript」JS四种跨域方式详解

超详细而且带 Demo 的 JavaScript 跨域指南来了!javascript

本文基于你了解 JavaScript 的同源策略,而且了解使用跨域跨域的理由。html

1. JSONP

首先要介绍的跨域方法必然是 JSONP。java

如今你想要获取其余网站上的 JavaScript 脚本,你很是高兴的使用 XMLHttpRequest 对象来获取。可是浏览器一点儿也不配合你,无情的弹出了下面的错误信息:git

XMLHttpRequest cannot load http://x.com/main.dat. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://y.com' is therefore not allowed access.

你内心确定会想,我难道要用后台作个爬虫来获取这个数据吗?!(;°○° )
为了不这种蛋疼的事情发生,JSONP 就派上用场了。github

<script> 标签是不受同源策略的限制的,它能够载入任意地方的 JavaScript 文件,而并不要求同源。segmentfault

因此 JSONP 的理念就是,我和服务端约定好一个函数名,当我请求文件的时候,服务端返回一段 JavaScript。这段 JavaScript 调用了咱们约定好的函数,而且将数据当作参数传入。
很是巧合的一点(其实并非),JSON 的数据格式和 JavaScript 语言里对象的格式正好相同。因此在咱们约定的函数里面能够直接使用这个对象。跨域

光说不练假把式,让咱们来看一个例子:浏览器

你须要获取数据的页面 index.html:安全

<script>
    function getWeather(data) {
        console.log(data);
    }
</script>

<script src="http://x.y.com/xx.js">

http://x.y.com/xx.js 文件内容:框架

getWeather({
    "城市": "北京",
    "天气": "大雾"
});

咱们能够看到,在咱们定义了 getWeather(data) 这个函数后,直接载入了 xx.js。
在这个脚本中,执行了 getWeather 函数,并传入了一个对象。而后咱们在这个函数中将这个对象输出到 console 中。

这就是整个 JSONP 的流程。

2. document.domain

使用条件:

  1. 有其余页面 window 对象的引用。
  2. 二级域名相同。
  3. 协议相同。
  4. 端口相同。

document.domain 默认的值是整个域名,因此即便两个域名的二级域名同样,那么他们的 document.domain 也不同。

使用方法就是将符合上述条件页面的 document.domain 设置为一样的二级域名。这样咱们就可使用其余页面的 window 对象引用作咱们想作的任何事情了。(╯▔▽▔)╯

补充知识:

  • x.one.example.com 和 y.one.example.com 能够将 document.domain 设置为 one.example.com,也能够设置为 example.com。
  • document.domain 只能设置为当前域名的一个后缀,而且包括二级域名或以上(.edu.cn 这种整个算顶级域名)。

咱们直接操刀演示,用两个网站 http://wenku.baidu.com/http://zhidao.baidu.com/
这两个网站都是 http 协议,端口都是 80, 且二级域名都是 baidu.com。

打开 http://wenku.baidu.com/,在 console 中输入代码:

document.domain = 'baidu.com';

var otherWindow = window.open('http://zhidao.baidu.com/');

咱们如今已经发现百度知道的网页已经打开了,在百度知道网页的 console 中输入如下代码:

document.domain = 'baidu.com';

如今回到百度文库的网页,咱们就可使用百度知道网页的 window 对象来操做百度知道的网页了。例如:

var divs = otherWindow.document.getElementsByTagName('div');

上面这个例子的使用方法并不常见,可是很是详细的说明了这种方法的原理。
这种方法主要用在控制 <iframe> 的状况中。

好比个人页面(http://one.example.com/index.... <iframe>

<iframe id="iframe" src="http://two.example.com/iframe.html"></iframe>

咱们在 iframe.html 中使用 JavaScript 将 document.domain 设置好,也就是 example.com。

在 index.html 执行如下脚本:

var iframe = document.getElementById('iframe');

document.domain = 'example.com';

iframe.contentDocument; // 框架的 document 对象
iframe.contentWindow; // 框架的 window 对象

这样,咱们就能够得到对框架的彻底控制权了。

补充知识(绝对干货):
当两个页面不作任何处理,可是使用了框架或者 window.open() 获得了某个页面的 window 对象的引用,咱们能够直接访问的属性有哪些?

方法
window.blur
window.close
window.focus
window.postMessage
window.location.replace
属性 权限
window.closed 只读
window.frames 只读
window.length 只读
window.location.href 只写
window.opener 只读
window.parent 只读
window.self 只读
window.top 只读
window.window 只读

3. window.name

咱们来看如下一个场景:

随意打开一个页面,输入如下代码:

window.name = "My window's name";
location.href = "http://www.qq.com/";

再检测 window.name :

window.name; // My window's name

能够看到,若是在一个标签里面跳转网页的话,咱们的 window.name 是不会改变的。
基于这个思想,咱们能够在某个页面设置好 window.name 的值,而后跳转到另一个页面。在这个页面中就能够获取到咱们刚刚设置的 window.name 了。

因为安全缘由,浏览器始终会保持 window.namestring 类型。

这个方法也能够应用到与 <iframe> 的交互上来。

个人页面(http://one.example.com/index.... <iframe>

<iframe id="iframe" src="http://omg.com/iframe.html"></iframe>

在 iframe.html 中设置好了 window.name 为咱们要传递的字符串。
咱们在 index.html 中写了下面的代码:

var iframe = document.getElementById('iframe');
var data = '';

iframe.onload = function() {
    data = iframe.contentWindow.name;
};

定睛一看,为毛线报错?
细心的读者们确定已经发现了,两个页面彻底不一样源啊!
因为 window.name 不随着 URL 的跳转而改变,因此咱们使用一个暗黑技术来解决这个问题:

var iframe = document.getElementById('iframe');
var data = '';

iframe.onload = function() {
    iframe.onload = function(){
        data = iframe.contentWindow.name;
    }
    iframe.src = 'about:blank';
};

或者将里面的 about:blank 替换成某个同源页面(最好是空页面,减小加载时间)。

补充知识:
about:blankjavascript:data: 中的内容,继承了载入他们的页面的源。

这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,能够从任意页面获取 string 类型的数据。

4. [HTML5] postMessage

在 HTML5 中, window 对象增长了一个很是有用的方法:

windowObj.postMessage(message, targetOrigin);
  • windowObj: 接受消息的 Window 对象。
  • message: 在最新的浏览器中能够是对象。
  • targetOrigin: 目标的源,* 表示任意。

这个方法很是强大,无视协议,端口,域名的不一样。下面是烤熟的栗子:

var windowObj = window; // 能够是其余的 Window 对象的引用
var data = null;

addEventListener('message', function(e){
    if(e.origin == 'http://jasonkid.github.io/fezone') {
        data = e.data;
        
        e.source.postMessage('Got it!', '*');
    }
});

message 事件就是用来接收 postMessage 发送过来的请求的。函数参数的属性有如下几个:

  • origin: 发送消息的 window 的源。
  • data: 数据。
  • source: 发送消息的 Window 对象。

Demo

https://github.com/JasonKid/f...

两种服务端相关跨域方法

「JavaScript」两种服务端相关跨域方法详解 ← 反向代理、CORS方法请点这里

以为不错的话按顶部的推荐,让更多人看到吧~ㄟ(▔▽▔ㄟ)

相关文章
相关标签/搜索