- 浏览: 1163548 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (224)
- Web UI (11)
- Dynamic Language (7)
- Framework (9)
- Note & Try (17)
- JavaScript (38)
- Ant/Gant/Maven (2)
- Database (5)
- Software Engineering (13)
- Career (29)
- Team Management (5)
- Performance (12)
- Algorithm (17)
- News & Commets (23)
- System Design (17)
- OO Design (8)
- API Design (3)
- Programming Paradigms (8)
- Asynchronous Programming (5)
- Architecture (6)
最新评论
-
a2320064997:
请问博主,排序的动图是怎么做出来的?
排序算法一览(二):归并类排序、分布类排序和混合类排序 -
你的微笑我得阳光:
试试验证码
reCAPTCHA项目 -
mack:
一般采用json
对象转换的问题 -
fly_hyp:
我也做了一个中文编程软件,叫趣智思成
一些中文编程语言 -
facingSun:
受教了
前端解耦的一个最简单示例
[转]疯狂的跨域技术
原帖地址:http://itgeeker.com/mathml/readpaper?pid=53
JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。
JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤为重要。根据这个策略,在baidu.com下的页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不同的子域名之间的页面也不能通过JavaScript代码互相访问。对于Ajax的影响在于,通过XMLHttpRequest实现的Ajax请求,不能向不同的域提交请求,例如,在abc.example.com下的页面,不能向def.example.com提交Ajax请求,等等。
然而,当进行一些比较深入的前端编程的时候,不可避免地需要进行跨域操作,这时候“同源策略”就显得过于苛刻。本文就这个问题,概括了跨域所需要的一些技术。
下面我们分两种情况讨论跨域技术:首先讨论不同子域的跨域技术,然后讨论完全不同域的跨域技术。
(一)不同子域的跨域技术。
我们分两个问题来分别讨论:第一个问题是如何跨不同子域进行JavaScript调用;第二个问题是如何向不同子域提交Ajax请求。
先来解决第一个问题,假设example.com域下有两个不同子域:abc.example.com和def.example.com。现在假设在def.example.com下面有一个页面,里面定义了一个JavaScript函数:
function funcInDef() {
.....
}
我们想在abc.example.com下的某个页面里调用上面的函数。再假设我们要讨论的abc.example.com下面的这个页面是以iframe形式嵌入在def.example.com下面那个页面里的,这样我们可能试图在iframe里做如下调用:
window.top.funcInDef();
好,我们注意到,这个调用是被前面讲到的“同源策略”所禁止的,JavaScript引擎会直接抛出一个异常。
为了实现上述调用,我们可以通过修改两个页面的domain属性的方法做到。例如,我们可以将上面在abc.example.com和def.example.com下的两个页面的顶端都加上如下的JavaScript代码片段:
<script type="text/javascript">
document.domain = "example.com";
</script>
这样,两个页面就变为同域了,前面的调用也可以正常执行了。
这里需要注意的一点是,一个页面的document.domain属性只能设置成一个更顶级的域名(除了一级域名),但不能设置成比当前域名更深层的子域名。例如,abc.example.com的页面只能将它的domain设置成example.com,不能设置成sub.abc.example.com,当然也不能设置成一级域名com。
上面的例子讨论的是两个页面属于iframe嵌套关系的情况,当两个页面是打开与被打开的关系时,原理也完全一样。
下面我们来解决第二个问题:如何向不同子域提交Ajax请求。
通常情况下,我们会用与下面类似的代码来创建一个XMLHttpRequest对象:
factories = [
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
function newRequest() {
for(var i = 0; i < factories.length; i++) {
try{
var factory = factories[i];
return factory();
} catch(e) {}
}
return null;
}
上面的代码中引用ActiveXObject,是为了兼容IE6系列浏览器。每次我们调用newRequest函数,就获得了一个刚刚创建的Ajax对象,然后用这个Ajax对象来发送HTTP请求。例如,下面的代码向abc.example.com发送了一个GET请求:
var request = newRequest();
request.open("GET", "http://abc.example.com" );
request.send(null);
假设上面的代码包含在一个abc.example.com域名下的页面里,则这个GET请求可以正常发送成功,没有任何问题。然而,如果现在要向def.example.com发送请求,则出现跨域问题,JavaScript引擎抛出异常。
解决的办法是,在def.example.com域下放置一个跨域文件,假设叫crossdomain.html;然后将前面的newRequest函数的定义移到这个跨域文件中;最后像之前修改document.domain值的做法一样,在crossdomain.html文件和abc.example.com域下调用Ajax的页面顶端,都加上:
<script type="text/javascript">
document.domain = "example.com";
</script>
为了使用跨域文件,我们在abc.example.com域下调用Ajax的页面中嵌入一个隐藏的指向跨域文件的iframe,例如:
<iframe name="xd_iframe" style="display:none" src="http://def.example.com/crossdomain.html"></iframe>
这时abc.example.com域下的页面和跨域文件crossdomain.html都在同一个域(example.com)下,我们可以在abc.example.com域下的页面中去调用crossdomain.html中的newRequest函数:
var request = window.frames["xd_iframe"].newRequest();
这样获得的request对象,就可以向http://def.example.com发送HTTP请求了。
(二)完全不同域的跨域技术。
如果顶级域名都不相同,例如example1.com和example2.com之间想通过JavaScript在前端通信,则所需要的技术更复杂些。
在讲解不同域的跨域技术之前,我们首先明确一点,下面要讲的技术也同样适用于前面跨不同子域的情况,因为跨不同子域只是跨域问题的一个特例。当然,在恰当的情况下使用恰当的技术,能够保证更优的效率和更高的稳定性。
简言之,根据不同的跨域需求,跨域技术可以归为下面几类:
- JSONP跨域GET请求
- 通过iframe实现跨域
- flash跨域HTTP请求
- window.postMessage
下面详细介绍各种技术。
1. JSONP。
利用在页面中创建<script>节点的方法向不同域提交HTTP请求的方法称为JSONP,这项技术可以解决跨域提交Ajax请求的问题。JSONP的工作原理如下所述:
假设在http://example1.com/index.php这个页面中向http://example2.com/getinfo.php提交GET请求,我们可以将下面的JavaScript代码放在http://example1.com/index.php这个页面中来实现:
var eleScript= document.createElement("script");
eleScript.type = "text/javascript";
eleScript.src = "http://example2.com/getinfo.php";
document.getElementsByTagName("HEAD")[0].appendChild(eleScript);
当GET请求从http://example2.com/getinfo.php返回时,可以返回一段JavaScript代码,这段代码会自动执行,可以用来负责调用http://example1.com/index.php页面中的一个callback函数。
JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
2. 通过iframe实现跨域。
iframe跨域的方式,功能强于JSONP,它不仅能用来跨域完成HTTP请求,还能在前端跨域实现JavaScript调用。因此,完全不同域的跨域问题,通常采用iframe的方式来解决。
与JSONP技术通过创建<script>节点向不同的域提交GET请求的工作方式类似,我们也可以通过在http://example1.com/index.php页面中创建指向http://example2.com/getinfo.php的iframe节点跨域提交GET请求。然而,请求返回的结果无法回调http://example1.com/index.php页面中的callback函数,因为受到“同源策略”的影响。
为了解决这个问题,我们需要在example1.com下放置一个跨域文件,比如路径是http://example1.com/crossdomain.html。
当http://example2.com/getinfo.php这个请求返回结果的时候,它大体上有两个选择。
第一个选择是,它可以在iframe中做一个302跳转,跳转到跨域文件http://example1.com/crossdomain.html,同时将返回结果经过URL编码之后作为参数缀在跨域文件URL后面,例如http://example1.com/crossdomain.html?result=<URL-Encoding-Content>。
另一个选择是,它可以在返回的页面中再嵌入一个iframe,指向跨域文件,同时也是将返回结果经过URL编码之后作为参数缀在跨域文件URL后面。
在跨域文件中,包含一段JavaScript代码,这段代码完成的功能,是从URL中提取结果参数,经过一定处理后调用原来的http://example1.com/index.php页面中的一个预先约定好的callback函数,同时将结果参数传给这个函数。http://example1.com/index.php页面和跨域文件是在同一个域下的,因此这个函数调用可以通过。跨域文件所在iframe和原来的http://example1.com/index.php页面的关系,在前述第一种选择下,后者是前者的父窗口,在第二种选择下,后者是前者的父窗口的父窗口。
根据前面的叙述,有了跨域文件之后,我们就可以实现通过iframe方式在不同域之间进行JavaScript调用。这个调用过程可以完全跟HTTP请求无关,例如有些站点可以支持动态地调整在页面中嵌入的第三方iframe的高度,这其实是通过在第三方iframe里面检测自己页面的高度变化,然后通过跨域方式的函数调用将这个变化告知父窗口来完成的。
既然利用iframe可以实现跨域JavaScript调用,那么跨域提交POST请求等其它类型的HTTP请求就不是难事。例如我们可以跨域调用目标域的JavaScript代码在目标域下提交Ajax请求(GET/POST/etc.),然后将返回的结果再跨域传原来的域。
使用iframe跨域,优点是功能强大,支持各种浏览器,几乎可以完成任何跨域想做的事情;缺点是实现复杂,要处理很多浏览器兼容问题,并且传输的数据不宜过大,过大了可能会超过浏览器对URL长度的限制,要考虑对数据进行分段传输等。
3. 利用flash实现跨域HTTP请求
据称,flash在浏览器中的普及率高达90%以上。
flash代码和JavaScript代码之间可以互相调用,并且flash的“安全沙箱”机制与JavaScript的安全机制并不尽相同,因此,我们可以利用flash来实现跨域提交HTTP请求(支持GET/POST等)。
例如,我们用浏览器访问http://example1.com/index.php这个页面,在这个页面中引用了http://example2.com/flash.swf这个flash文件,然后在flash代码中向http://example3.com/webservice.php发送HTTP请求。
这个请求能否被成功发送,取决于在example3.com的根路径下是否放置了一个crossdomain.xml以及这个crossdomain.xml的配置如何。flash的“安全沙箱”会保证:仅当example3.com服务器在根路径下确实放置了crossdomain.xml文件并且在这个文件中配置了允许接受来自example2.com的flash的请求时,这个请求才能真正成功。下面是一个crossdomain.xml文件内容的例子:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="example2.com" />
</cross-domain-policy>
4. window.postMessage
window.postMessage是HTML标准的下一个版本HTML5支持的一个新特性。受当前互联网技术突飞猛进的影响,浏览器跨域通信的需求越来越强烈,HTML标准终于把跨域通信考虑进去了。但目前HTML5仍然只是一个draft。
window.postMessage是一个安全的实现直接跨域通信的方法。但是目前并不是所有浏览器都能支持,只有Firefox 3、Safari 4和IE8可以支持这个调用。
使用它向其它窗口发送消息的调用方式大概如下:
otherWindow.postMessage(message, targetOrigin);
在接收的窗口,需要设置一个事件处理函数来接收发过来的消息:
window.addEventListener("message", receiveMessage, false);function receiveMessage(event){ if (event.origin!== "http://example.org:8080") return;}消息包含三个属性:data、origin(携带发送窗口所在域的真实信息)和source(代表发送窗口的handle)。
安全性考虑:使用window.postMessage,必需要使用消息的origin和source属性来验证发送者的身份,否则会造成XSS漏洞。
window.postMessage在功能上同iframe实现的跨域功能同样强大,并且使用简单,效率更高,但缺点是它目前在浏览器兼容方面有待提高。
总结完所有的跨域方式之后,我们要时刻铭记,虽然跨域技术能给你带来更多的功能,催生出更灵活和更加平台化的产品,但是功能的放开也总是意味着安全的风险。在实现跨域技术的每个步骤和细节,都要时刻在头脑中考虑到对安全带来的影响,避免成为XSS攻击的漏洞。
俺在转载基础上,再补充两个实现:
1、百度在Ajax跨域的时候用了这样的办法:往head里面加一个script src=xxx,因为script标签是可以跨域的。
2、Google的点击计数则这样做:new img().src=...;也跨域了。。。
发表评论
-
JavaScript 3D图表
2013-08-24 19:36 3134在说3D图表以前,首先要明确两个概念,一个是数据的维度,一个 ... -
几道容易出错的JavaScript题目
2013-07-07 10:34 2272下面这几道JavaScript题目大多来自于周五的一个小分享 ... -
JavaScript使用for循环时出现的问题
2013-05-26 00:36 1663这个问题的讨论最初来自公司内部邮件,我只是把这个问题的讨论内 ... -
DNS劫持
2013-04-30 13:59 2179想谈一谈这个话题是因为最近有一位朋友抱怨他的博客在某些用户某 ... -
你没有抓住Promises的要点
2013-04-21 20:52 2470注:这篇文章翻译自《You're Missing the P ... -
程序员,都去写一写前端代码吧
2013-01-19 01:16 2682你可以认为我是一个极 ... -
用JavaScript截图
2013-01-08 23:13 7658使用JavaScript截图,这里我要推荐两款开源组件: ... -
JQuery表格插件介绍:Flexigrid和DataTables
2012-12-27 11:35 8981JQuery的表格插件有很多。Flexigrid和Dat ... -
Flot介绍
2012-12-22 18:56 2371最近在项目里面要用到JavaScript来绘制图表,JQ ... -
Function Invocation Patterns
2012-11-04 17:46 1372今天看到微博上大家在讨论一个JavaScript的小问题 ... -
d3介绍
2012-10-31 00:17 2611D3.js是一个基于数据的操作文档的JavaScript ... -
Dart,你凭什么挑战JavaScript?
2012-09-26 08:46 5852不妨先来打量一下JavaScript。JavaScrip ... -
Backbone.js介绍
2012-05-08 22:57 4465注:教程请参见这里(本文有很多内容都是从这里翻译的),官方网站 ... -
关于CommonJS
2012-03-26 00:37 17290老实说,之前我对CommonJS也是一无所知,直到不久前Nod ... -
同步、异步转化和任务执行
2012-01-24 22:23 4238正如动静是相对的概念,有了它们,世界才充满盎然生气;变和不变也 ... -
JavaScript实现继承的几种方式
2012-01-07 23:21 12407在这篇文章中,介绍了 ... -
JavaScript重构(十):强化对象封装和模块封装
2011-09-19 22:44 36821、类本身就是一种封装形式,先来看看最简单的封装,JavaSc ... -
JavaScript 的 delete 用法
2011-01-09 11:59 17361、 var o = {}; o.x = new Ob ... -
服务器端JavaScript
2011-01-11 00:05 1348JSConf2010的重要议题之一:node.js。 不要觉 ... -
JSConf 2010 (一):介绍、Google Chrome Frame 和 GitHub
2011-01-12 00:15 1728一年一度的JSConf大会又召开,这是2010的官网 http ...
相关推荐
《疯狂Ajax讲义》第三版是一本深入探讨Ajax技术的专业书籍,其源码包包含了第11章的详细实现和示例。Ajax,全称Asynchronous JavaScript and XML,是一种在无需刷新整个网页的情况下,能够更新部分网页内容的技术。...
《疯狂Ajax讲义源码(第二版)》是一份针对Web开发中Ajax技术的深入学习资料,主要聚焦于JavaScript和服务器端交互的核心技术。Ajax,全称Asynchronous JavaScript and XML,是一种在无需重新加载整个网页的情况下,...
《疯狂Ajax讲义》是由知名IT作者李刚编写的一本深入解析Ajax技术的教程,其源代码是书中实例和练习的实现,旨在帮助读者更好地理解和掌握Ajax的核心概念和技术。Ajax,全称Asynchronous JavaScript and XML(异步...
- **JSONP**(JSON with Padding)是一种利用`<script>`标签不受同源策略限制的特点来实现跨域请求的技术。 - JSONP的实现原理是动态插入`<script>`标签,并将回调函数名作为参数传递给服务器,服务器返回的结果会在...
【标题】"疯狂Ajax讲义随书光盘 17 重新上传"涉及的主要知识点是Web开发中的Ajax技术,这是Asynchronous JavaScript and XML(异步JavaScript与XML)的缩写,它是一种在无需重新加载整个网页的情况下,能够更新部分...
《疯狂Ajax讲义》第三版源码是一套深入学习Ajax技术的重要资料,它包含了Web开发中的前端交互核心技术。Ajax,全称Asynchronous JavaScript and XML,是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术...
《疯狂Ajax》的源码涵盖了各种Ajax应用实例,包括简单的GET请求、POST提交、异步文件上传、跨域请求、JSONP等,是学习和实践Ajax的宝贵资源。通过对这些源码的学习,可以加深对Ajax工作原理的理解,掌握实际开发中的...
【标题】"疯狂Ajax讲义随书光盘14 重新上传"主要涵盖了Ajax技术在Web开发中的深度应用,这是一份重要的学习资料,旨在帮助读者深入理解和掌握Ajax技术。Ajax,即Asynchronous JavaScript and XML(异步JavaScript与...
【标题】"疯狂Ajax光盘16章源码(上)"揭示了这是一份与Ajax技术相关的教学资源,可能是某个教程或书籍的配套代码,包含前16章节的源代码。Ajax,全称为Asynchronous JavaScript and XML,是一种在无需重新加载整个...
- **教程文档**:深入解释Ajax技术,包括XMLHttpRequest的使用、跨域问题、缓存策略等。 - **练习题与答案**:检验和巩固学习成果,提高技能水平。 - **调试工具和技巧**:介绍如何利用开发者工具进行Ajax请求的调试...
《疯狂Ajax讲义源码2.rar》是一份与Ajax技术相关的学习资料,包含了两部分的源代码:07和06。Ajax,全称为Asynchronous JavaScript and XML(异步JavaScript和XML),是一种在无需重新加载整个网页的情况下,能够...
在《疯狂Ajax讲义》中,我们可以期待学习到以下关键知识点: 1. **基础概念**:首先,你需要理解Ajax的基本原理,包括XMLHttpRequest对象,它是Ajax的核心,用于在后台与服务器通信。同时,还会涉及JavaScript的DOM...
《疯狂Ajax讲义02》是一本专注于Ajax技术的深入学习资料,主要涵盖了Ajax的基础概念、核心技术和实际应用。Ajax,全称为"Asynchronous JavaScript and XML"(异步JavaScript与XML),是一种在无需重新加载整个网页的...
《疯狂Ajax讲义 第三版》是一本深入探讨Ajax技术的专业书籍,其源码提供了丰富的实践示例,帮助读者理解并掌握Ajax的核心概念和技术。在第十章中,我们预计会学习到Ajax技术在实际项目中的高级应用和技巧。Ajax,...
《疯狂Ajax讲义源码5(2)》这个压缩包文件是针对Web开发中的Ajax技术进行深入学习的一个资源集合。Ajax,全称Asynchronous JavaScript and XML,是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。这...
《疯狂Ajax讲义》是关于Web开发领域中Ajax技术的一部深入详解的教材,第17章涵盖了Ajax技术的关键知识点和实践应用。Ajax,全称为"Asynchronous JavaScript and XML",是一种在无需刷新整个网页的情况下,能够更新...
《疯狂Ajax讲义源码3》是一份针对Ajax技术深入探讨的资料,包含了丰富的实践代码和实例解析。Ajax,全称Asynchronous JavaScript and XML(异步JavaScript和XML),是一种在无需刷新整个网页的情况下,能够更新部分...
【疯狂Ajax光盘16章源码(下)】是一个包含丰富Web开发资源的压缩包,专注于Ajax技术的深入学习和实践。这个压缩文件可能是某本名为“疯狂Ajax”的教材或教程的配套材料,提供了第16章及后续章节的全部源代码。Ajax...