AJAX的阻塞及跨域名解析

阻塞的AJAX请求

  我们先来证实一下请求的阻塞情况吧。我们使用如下的代码:

连续发起三个请求

function simpleRequest()
{
   var request = new XMLHttpRequest();
   request.open("POST", "Script.ashx");
   request.send(null);
}

function threeRequests()
{
   simpleRequest();
   simpleRequest();
   simpleRequest();
}

当执行threeRequests时就会连续发出3个相同域名的请求,还是通过统计图表来查看阻塞的效果,如图:

每个请求需要花费1.5秒的时间。很明显,第三个请求必须等到第一个请求结束之后才能执行,因此总共需要进行3秒多钟才能执行完毕。我们要改变的就是这个状况。

传统的跨域名异步请求解决方案

  AJAX安全性的唯一保证,似乎就是对于跨域名(Cross-Domain)AJAX请求的限制。除非打开本地硬盘的网页,或者在IE中将跨域名传输数据的限制打开,否则向其他域名发出AJAX请求都会被禁止。而且对于跨域名的判断非常严格,不同的子域名,或者相同域名的不同端口,都会被认作是不同的域名,我们不能向它们的资源发出AJAX请求。

  从表面上看起来似乎没有办法打破这个限制,还好我们有个救星,那就是iframe!

  iframe虽然不在标准中出现,但是由于它实在有用,FireFox也“不得不”对它进行了支持(类似的还有innerHTML)。网上已经有一些跨域名发出异步请求的做法,但是它们实在做的不好。它们的简单工作原理如下:在另一个域名下放置一个特定的页面文件作为Proxy,主页面将异步请求的信息通过Query String传递入iframe里的Proxy页面,Proxy页面在AJAX请求执行完毕后将结果放在自己location的hash中,而主页面会对iframe的src的hash值进行轮询,一旦发现它出现了改变,则通过hash值得到需要的信息。

  这个方法的实现比较复杂,而且功能有限。在IE和FireFox中,对于URL的长度大约可以支持2000个左右的字符。对于普通的需求它可能已经足够了,可惜如果真要传递大量的数据,这就远远不够了。与我们一会儿要提出的解决方案相比,可能它唯一的优势就是能够跨任意域名进行异步请求,而我们的解决方案只能突破子域名的限制。

  那么现在来看看我们的做法!

优雅地突破子域名的限制

  我们突破子域名限制的关键还是在于iframe。

  iframe是的好东西,我们能够跨过子域名来访问iframe里的页面对象,例如window和DOM结构,包括调用JavaScript(通过window对象)——我们将内外页面的document.domain设为相同就可以了。然后在不同子域名的页面发起不同的请求,把结果通过JavaScript进行传递即可。唯一需要的也仅仅是一个简单的静态页面作为Proxy而已。

  我们现在就来开始编写一个原形,虽然简单,但是可以说明问题。

  首先,我们先来编写一个静态页面,作为放在iframe里的Proxy,如下:

SubDomainProxy.html

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
   <title>Untitled Page</title>
   <script type="text/javascript" language="javascript">
       document.domain = "test.com";

function sendRequest(method, url)
       {
           var request = new XMLHttpRequest();
           request.open(method, url);
           request.send(null);
       }
   </script>
</head>
<body>

</body>
</html>

  然后我们再编写我们的主页面:

http://www.test.com/Default.html

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
   <title>Untitled Page</title>
   <script type="text/javascript" language="javascript">
       document.domain = "test.com";

function simpleRequest()
       {
           var request = new XMLHttpRequest();
           request.open("POST", "Script.ashx");
           request.send(null);
       }

function crossSubDomainRequest()
       {
           var proxy = document.getElementById("iframeProxy").contentWindow;
           proxy.sendRequest('POST', 'http://sub0.test.com/Script.ashx');
       }

function threeRequests()
       {
           simpleRequest();
           simpleRequest();
           crossSubDomainRequest();
       }
   </script>
</head>
<body>
   <input type="button" value="Request" onclick="threeRequests()" />
   <iframe src="http://sub0.test.com/SubDomainProxy.html" style="display:none;"
       id="iframeProxy"></iframe>
</body>
</html>

  当执行threeRequests方法时,将会同时请求http://www.test.com以及http://sub0.test.com两个不同域名下的资源。很明显,最后一个请求已经不会受到前两个请求的阻塞了 如图:


令人满意的结果!

  虽说只能突破子域名,但是这已经足够了,不是吗?我们为什么要强求任意域名之间能够异步通讯呢?更何况我们的解决方案是多么的优雅!在下一篇文章中,我们将会为ASP.NET AJAX客户端实现一个完整的CrossSubDomainRequestExecutor,它会自动判断是否正在发出跨子域名的请求,并选择AJAX请求的方式。这样,客户端的异步通讯层就会对开发人员完全透明。世上还会有比这更令人愉快的事情吗?:)

注意事项

  可能以下几点值得一提:

我在出现这个想法之后也作了一些尝试,最后发现创建XMLHttpRequest对象,调用open方法和send方法都必须在iframe中的页面中执行才能够在IE和FireFox中成功发送AJAX请求。
在上面的例子中,我们向子域名请求的的路径是http://sub0.test.com/Script.ashx。请注意,完整的子域名不可以省略,否则在FireFox下就会出现权限不够的错误,在调用open方法时就会抛出异常——似乎FireFox把它当作了父页面域名的资源了。
Windows Live Contacts Gadget使用了一种叫做Channel的技术,用于解决跨任意域名传递数据的问题,我相当佩服微软技术人员的创造力。Channel技术是一种优秀的解决跨域名异步请求问题的解决方案,而且如果将它封装成了组件,那么使用起来也会相当优雅(似乎微软已经准备这么做了)。不过它和我们现在需要解决的问题并不相同,如果有机会的话,我也会详细的解释一下Channel技术——但不是现在,因为我觉得我还没有完全理解这个技术本身。

原文:
作者:赵劼 http://www.cnblogs.com/JeffreyZhao/archive/2007/02/02/Break_the_Browsers_Restrictions_6.html

(0)

相关推荐

  • 一步一步学asp.net Ajax登录设计实现解析

    任务需求:做一个登录,拥有自动记住账号和密码的功能,要保证安全性,ajax,无刷新,良好的用户体验.(母板页) 这是前台页面,要求实现用户登录 首先我们分析, 用户需求: 1. 登录以后,登录框隐藏,并且欢迎登录的框显示,并且,左上角登录的按钮消失,安全退出显示. 2. 如果选择记住帐号和密码,下次登录直接登录,并且保证安全性. 实现过程: 首先,登录的时候发出ajax请求,用户验证登录,登录以后,保存当前用户名和密码到cookies中,注意,密码要用md5加密,md5是根据用户的机器配置生成的

  • 全面解析Ajax综合应用(全)

    AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 JavaScript和XML(标准通用标记语言的子集). AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新. 传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个网页页面.

  • 用JQuery 实现AJAX加载XML并解析的脚本

    1,Content-Type 很多时候无法解析就是Content-Type的问题. 如果本身就是xml文件,请跳过这一步 动态生成的XML一定要将其设置为text/xml,否则默认就是text/html也就是普通的文本了. 常见语言的Content-Type设置 复制代码 代码如下: header("Content-Type:text/xml"); //php response.ContentType="text/xml" //asp response.setHea

  • jQuery Ajax 全解析

    jQuery确实是一个挺好的轻量级的JS框架,能帮助我们快速的开发JS应用,并在一定程度上改变了我们写JavaScript代码的习惯. 废话少说,直接进入正题,我们先来看一些简单的方法,这些方法都是对jQuery.ajax()进行封装以方便我们使用的方法,当然,如果要处理复杂的逻辑,还是需要用到jQuery.ajax()的(这个后面会说到). 1. load( url, [data], [callback] ) :载入远程 HTML 文件代码并插入至 DOM 中. url (String) :

  • Jquery ajax不能解析json对象,报Invalid JSON错误的原因和解决方法

    下面说一下,最近在使用jquery 1.4中使用$.ajax()方法解析json对象遇到的问题. Json对象是: 复制代码 代码如下: [{name:'二手房出售',infoCount:0,pageUrl:'/ershoufang'},{name:'二手房求购',infoCount:0,pageUrl:'/qiugou'},{name:'二手房装修',infoCount:0,pageUrl:'/esfzhuangxiu'},{name:'二手回收',infoCount:0,pageUrl:'/

  • jQuery Ajax 实例全解析

    废话少说,直接进入正题,我们先来看一些简单的方法,这些方法都是对jQuery.ajax()进行封装以方便我们使用的方法,当然,如果要处理复杂的逻辑,还是需要用到jQuery.ajax()的(这个后面会说到). 1. load( url, [data], [callback] ) :载入远程 HTML 文件代码并插入至 DOM 中. url (String) : 请求的HTML页的URL地址. data (Map) : (可选参数) 发送至服务器的 key/value 数据. callback (

  • jQuery Ajax使用 全解析

    废话少说,直接进入正题,我们先来看一些简单的方法,这些方法都是对jQuery.ajax()进行封装以方便我们使用的方法,当然,如果要处理复杂的逻辑,还是需要用到jQuery.ajax()的(这个后面会说到). 1. load( url, [data], [callback] ) :载入远程 HTML 文件代码并插入至 DOM 中. url (String) : 请求的HTML页的URL地址. data (Map) : (可选参数) 发送至服务器的 key/value 数据. callback (

  • jquery ajax请求实例深入解析

    jquery中封装了一些ajax请求的方法,很实用. 比如.ajaxComplete()--请求完成时.ajaxError()--请求失败时.ajaxSend()--在Ajax请求发送时附加一个function去执行.ajaxStart()--请求开始时,.ajaxStop()--请求结束时.ajaxSuccess()--请求成功时.load()--从服务端加载数据并将返回的HTML替换到选择的元素中jQuery.post()--使用HTTP POST请求加载服务端数据.serialize()-

  • Javascript(AJAX)解析XML的代码(兼容FIREFOX/IE)

    复制代码 代码如下: //导入js文件 function getResult(url, ready) { var xmlHttp; var r = function() { if (xmlHttp.readyState == 4) { if (xmlHttp.status == 200) { //alert(isIE); var xmlstr; var xmldoc; var isIE = !!(window.attachEvent && !window.opera); if (isIE)

  • 浅析ajax请求json数据并用js解析(示例分析)

    自从接触了jquery就喜欢上了前端开发,而且深深感受到了前端开发的强大与重要之处.同时也想为asp.net鸣不平,事实上asp.net并没有臃肿,说它臃肿的人无非是那些不了解它的人,可能他们看见过一些asp.net低级程序员在不断往页面里拖控件,然后发现生成的页面中含有大量的垃圾代码,而且几乎把所有的逻辑处理都写在了服务器端,觉得服务器压力太大了.事实上,刚入门asp.net的人会有拖控件的习惯,但是当你再深入你会发现,最终asp.net的开发模式还是跟PHP.jsp等其它web开发模式是一样

随机推荐