「JavaScript」四种跨域方式详解
2015-10-03 18:32
357 查看
原文:http://segmentfault.com/a/1190000003642057
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
使用条件:有其他页面
window对象的引用。
二级域名相同。
协议相同。
端口相同。
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.html)中内嵌了一个
<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.html)中内嵌了一个
<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:blank,
javascript:和
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/fezone/tree/master/JavaScript/
两种服务端相关跨域方法
「JavaScript」两种服务端相关跨域方法详解
相关文章推荐
- 《高性能javascript》一书要点和延伸(上)
- 【JavaScript】SVGTool: SVG常用方法库
- backbone.js之Model篇 简单总结和深入(2)
- jsp或者html页面编码格式更改
- jse中将数据反转
- jse中将数据反转
- html5移动开发--js温馨提示
- 自定义jsp标签
- 随笔分类 - 无废话ExtJs系列教程
- javascript 中检测数据类型的方法
- 解决jetty runner锁定js
- javascript基础(下)
- JSon 事件格式化
- JSP/Servlet 工作原理
- javascript 中的类数组和数组
- ExtJS4 根据分配不同的树形菜单在不同的角色登录后
- js文件引入顺序问题
- ExtJS得知--------Ext.Element学习的查询方法(示例)
- 151003-动起来-Javascript
- JS(ajax笔记)