跨域问题实践总结! 上(JSONP/document.domain/window.name)

1. JSONP

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

现在你想要获取其他网站上的 JavaScript 脚本,你非常高兴的使用 XMLHttpRequest 对象来获取。但是浏览器一点儿也不配合你,无情的弹出了下面的错误信息:

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 就派上用场了。

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

所以 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-----------------这个方法有点问题,执行iframe.src之后iframe中的页面刷新后变量就消失了,取不到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.name 是 string 类型。

这个方法也可以应用到与 <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 类型的数据。

1. JSONP

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

现在你想要获取其他网站上的 JavaScript 脚本,你非常高兴的使用 XMLHttpRequest 对象来获取。但是浏览器一点儿也不配合你,无情的弹出了下面的错误信息:

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 就派上用场了。

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

所以 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.name 是 string 类型。

这个方法也可以应用到与 <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 类型的数据。

时间: 2024-11-05 22:57:25

跨域问题实践总结! 上(JSONP/document.domain/window.name)的相关文章

跨域问题实践总结!下(JSONP/document.domain/window.name)

4. [HTML5] postMessage 问题: 对于跨域问题,研究了一下html5的postMessage,写了代码测试了一下,感觉html5新功能就是好用啊.此文仅使用html5的新特性postMessage,演示其执行过程和效果: 方法解释:postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档.多窗口.跨域消息传递.postMessage(data,origin)方法接受两个参数:1.data:你需要传递的消息,消息传递的格式有一定要求:参数可

常用跨域方法实践(二)

本文承接 上一篇博文,上一篇博文介绍了跨域的相关概念.测试demo的相关配置和 JSONP 和 CORS 两种跨域方式的实现.本文主要介绍 document.domain . URL.hash . cross-fragment . window.name 和 postMessage 这五种方式的跨域实现. document.domain 如果 A 源和 B 源具有相同的父域名,通过设置 document.domain 属性,就很容易使其相互通信.在 HTML 规范中document.domain

跨域解决方案二:使用JSONP实现跨域

跨域的实现方式有多种,除了 上篇文章 提到的CORS外,常见的还有JSONP.HTML5.Flash.iframe.xhr2等. 这篇文章对JSONP的跨域原理进行了探索,并将我的心得记录在这里和大家分享. JSONP跨域原理探秘 我们知道,使用 XMLHTTPRequest 对象发送HTTP请求时,会遇到 同源策略 问题,域不同请求会被浏览器拦截. 那么是否有方法能绕过 XMLHTTPRequest 对象进行HTTP跨域请求呢? 换句话说,不使用 XMLHTTPRequest 对象是否可以发送

跨域知识(二)——JSONP

JSONP是服务器与客户端跨源通信的常用方法.最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小. 它的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制:服务器收到请求后,将数据放在一个指定名字的回调函数里传回来. 该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了. 如果对于callb

常用跨域方法实践(一)

这几天看了鬼道师兄的<跨终端Web>这本书,该书从解决实际业务出发,讲述了跨终端的优势与未来,受益良多.其中,书中第九章介绍了作者在阿里内部的一个参赛作品Storage,该作品巧妙的使用了跨域知识,让我见识到跨域其实不仅仅是JSONP.以前,对前端跨域这块或多或少有点了解,但真正动手实践的不是很多.于是,这段时间我好好整理了常用跨域方法的具体实现.本文,主要介绍了JSONP和CORS的实现方式. 相关概念: 只要协议.域名.端口有任何一个不同,都被当作是不同的域 JavaScript出于安全方

JSON跨域读取那点事(JSONP跨域访问)

最近在码一个小项目,需要远程读取json.因为需求很少,如果引用jquery使用其getjson方法就显得很浪费嘛= = 这篇文章很详细的解释了JSON跨域读取的前世今生,把原理讲得很透彻.特此分享. 原文链接:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html 前言: 由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强

jquery ajax跨域的完美解决方法(jsonp方式)

ajax跨域请求的问题,JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式,接下来为大家详细介绍下客户端JQuery.ajax的调用代码 今天在项目中需要做远程数据加载并渲染页面,直到开发阶段才意识到ajax跨域请求的问题,隐约记得Jquery有提过一个ajax跨域请求的解决方式,于是即刻翻出Jquery的API出来研究,发 JQuery对于Ajax的跨域请求有两类解决方案,不过都是只支持get方式.分别是JQuery的 jquery.ajax jsonp格式和jquer

SpringBoot多跨域请求的支持(JSONP)

在我们做项目的过程中,有可能会遇到跨域请求,所以需要我们自己组装支持跨域请求的JSONP数据,而在4.1版本以后的SpringMVC中,为我们提供了一个AbstractJsonpResponseBodyAdvice的类用来支持jsonp的数据(SpringBoot接收解析web请求是依赖于SpringMVC实现的).下面我们就看一下怎么用AbstractJsonpResponseBodyAdvice来支持跨域请求. 使用AbstractJsonpResponseBodyAdvice来支持跨域请求

Ajax跨域请求 同源策略与Jsonp

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现.同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指,域名,协议,端口相同.当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个