`
adong
  • 浏览: 35974 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

网页里做异步的跨域请求

阅读更多
网页制作Webjx文章简介:这篇文章将会探讨一下在网页里做异步的跨域请求,以及借助iframe来获取数据的方法。


这篇文章将会探讨一下在网页里做异步的跨域请求,以及借助iframe来获取数据的方法。
呃,本来我觉得这个话题没什么好说的了,因为如今好像没有几个web应用能离开这类request,google和facebook用iframe来做comet的时候也基本上把能hack的都hack遍了,所以我估计开发者社区里应该早就形成所谓的”最佳实践”(best practices)了罢。不过最近看到有一些关注前端技术的blog(比如realazy)在讨论相关的话题,发现还是有一些东西值得写下来。




一、借助script的异步跨域请求
先说跨域的问题,首先要指出的是,iframe里的js宿主对象一样也躲不开同源策略(Same Origin Policy),仅仅能解决二级域名的跨域而已,比如www.tudou.com和so.tudou.com,如果要请求某个八杆子打不到一起去的域名下的数据(例如你想搞mashup),建议老老实实的用script标签去请求JSONP罢。关于JSONP要附带说一下的是,jQuery对JSONP请求的封装方式很值得提倡:

1.$.getJSON(url, params + "&jsoncallback=?", function(json){
2.    /* do something */
3.});
用jsoncallback作为服务器端支持的标准jsonp参数,而每次执行这个方法都会用时间戳生成一个唯一的全局函数名,替换这个“?”,这个细节被封装到黑盒里,使用者不必了解,可以像普通的ajax请求一样,用匿名的回调函数作为最末尾的参数(这是jquery强调的风格),这种语法糖(syntactic sugar)的作用绝对不仅仅是让前端开发人员可以偷懒而已,对代码的可读性,兼容性和今后的维护都有好处。(我经常要向服务器端的开发人员解释这个道理,否则他们才不给你支持什么jsoncallback参数呢,直接给你返回一个“yy({……})”就算完工……囧)

二、利用前沿技术的跨域方法
当然了,我们还可以走一些目前来看比较野的路子来实现跨域,比如在页面里嵌入一个不到1K的swf,借助flashplayer向部署了crossdomain.xml的服务器请求数据,再用actionscript里的ExternalInterface类把数据还给javascript(我觉得这种方法忒有调用dll的感觉~大心)。

我们还可以指望ie8里支持的XDomainRequestAllowed,和firefox3.1支持的Access Control,甚至传说中的HTML5 socket……噢喔喔,多么甜美的梦……/掐一把脸蛋

三、用iframe直接发送跨域请求
跟script标签一样,iframe也可以用来替代ajax,而且在修改document.domain之后(比如上面提到的两个域名,可以设置document.domain = “tudou.com”),还可以解决部分跨域问题。

通过iframe请求数据的方法,最直接的莫过于在页面里动态的嵌入一个iframe标签,用它的src属性直接请求包含数据的网页,然后利用那个网页里的js把数据传给父页面,比如:

1.<iframe id="crossdomain" width="0" height="0" style="visibility:hidden;" src="http://yoursite.com/request_url/" ></iframe>
这种方法耦合的太紧,非常不推荐。你请求的URI代表一个资源,应该是单纯的数据,它会作为xml,json,js代码还是html来处理,这个并不重要,不应该把你的程序逻辑跟数据混杂到一起,数据也不应该因为跨域或不跨域,用iframe,script还是ajax来请求就变成完全不同的东西。

有人会说:为了让数据能够被JS处理,返回的内容难免有差异。——但是小的差异可以通过合理的封装隐藏起来,比如JQuery的getJSON方法

有人会说:请求的URI是一个动态页面,同样可以在URI里支持类似jsoncallback的参数,生成一个script标签和其中的JS代码,把数据“包裹”在JS里,比如请求“http://yoursite.com/request_url/?callback=cb1304344”,返回:

1.<script type="text/javascript">
2.document.domain="tudou.com";
3.top.cb1304344({ /* 数据 */ });
4.</script>
——首先,很多情况下你请求到的不会是动态页面,在这个到处都强调高负载的web世界里,你拿到的经常是squid之类的代理程序返回的缓存。其次,如果你请求的是HTML格式的文本,为了能作为JS代码来执行,服务器端必须对这段文本做转义和清理工作,而且安全性还不一定能保证(因为HTML里经常包含很多来自UGC的内容),如果你请求的是JSON格式的数据……那何必用iframe咧……直接嵌script罢……

四、用iframe直接请求数据的最佳实践
我推荐在上述方法的基础上做改良,首先在服务器端,直接返回数据本身,并且把数据“包裹”在一个textarea标签里,比如:

1.<textarea><div><p>yyyyy</p></div></textarea>
textarea的优点是可以支持任何格式的内容,而且这些内容不会在iframe子页面里解析(比如创建DOM树,执行JS),接下来前端要做的,只是在父页面里获取到子页面的DOM,把textarea的内容取出来(注意不能取innerHTML而要取value)。

这里存在一个判断iframe是否加载完成的问题,解决方法之一是在iframe标签上写onload事件,不过这样就需要显式的调用一个函数。

方法二如下:

1.(function(){
2.try{
3.    callback(document.getElementById('crossdomain').contentWindow.document.body.getElementsByTagName("TEXTAREA")[0].value);
4.}catch(e){
5.    setTimeout(arguments.callee,0);
6.    return;
7.}   
8.})();
最后我们可以封装出这样一个方法:

1.window.TUI = window.$ = {};
2./**
3.* @public 通过iframe异步请求数据
4.* @param {string}  url是请求的地址
5.* @param {function}  cb是处理返回数据的回调函数
6.*/
7.TUI.getIframeData = function(url, cb){
8.    var f = document.getElementById('crossdomain');
9.    if(f)
10.        f.src = url;
11.    else{
12.        var t = document.createElement("DIV");
13.        t.innerHTML = '<iframe id="crossdomain" width="0" height="0" style="visibility:hidden;" src="' + url + '" ></iframe>';
14.        document.body.appendChild(t.firstChild);
15.    }
16. 
17.    (function(){
18.    try{
19.        cb(document.getElementById('crossdomain').contentWindow.document.body.getElementsByTagName("TEXTAREA")[0].value);
20.    }catch(e){
21.        setTimeout(arguments.callee,0);
22.        return;
23.    }   
24.    })();
25.};
26. 
27. 
28.//像这样执行
29.$.getIframeData("http://yoursite.com/request_url/", function(data){
30.    /* do something */
31.});
只要再增加一个可选的param参数,这就是一个很标准的jQuery AJAX API,我们还可以在jQuery的$.get上面封装,增加一个是否跨域的判断,当这个request的URI修改成同样的域名后,自动切换到普通的AJAX方法来请求,把返回的文本用类似这样的正则/<(textarea)>(.+)<\/(textarea)>/删掉多余的字符,再传给回调函数,前端和服务器端都不用修改代码。

五、用iframe直接请求数据的缺陷
必须指出的是,iframe在ie里获取数据时会引发一些“小问题”,dojo的创始人Alex Russell把它们称作“灵异点击(phantom click)”和“噩梦般的指示器(throbber of doom)”,前者是指在iframe请求内容的时候会出现一次点击链接的音效(让用户怀疑闹鬼,多差的体验口牙!),后者是指iframe加载过程中,ie的界面上会出现正在读取的提示(比如左下的进度条,右上的图标)……好罢,其实以我个人的标准,这两个问题都可以无视……

这种方法还有一个明显的缺陷,就是只支持GET类型的请求。

六、用iframe结合ajax
不过iframe还有一种使用方法,不但可以避免上面提到的问题,也不需要服务器端做任何调整,简单来说:在iframe的src里调用一个包含ajax方法的页面,然后父页面调用这个方法来发起跟子页面同域名下的ajax请求。在土豆网的播放页面上,我使用这种方法请求用户评论统一接口里的HTML内容,例如这个WH40K:DOWII的视频:

http://www.tudou.com/programs/view/iPcprDz_LhI/

获得评论部分HTML的接口类似这样:

http://comments.tudou.com/itemcomment.srv?method=get&iid=21283123&page=1&tm=5&ban=1

这个接口在独立的一组服务器上实现,在视频播放页,豆单播放页,豆单封面,相册,个人主页都会被调用。由于包含大量用户提交的内容和复杂的HTML结构,如果用JSON形式,前端后端处理起来都效率低,此外,提交新评论,回复,删除,也会用到comments.tudou.com这个域名下的接口,而这些操作显然需要POST类型的请求。在这种需求下,借助iframe的AJAX方法

首先在comments.tudou.com域名下部署一个供iframe调用的跨域文件,感觉很像flashplayer的crossdomain.xml……

http://comments.tudou.com/crossdomain/index.html

可以看到源文件里仅仅包含一个stand-alone的ajax方法……呃……你觉得很眼熟?不用怀疑,就是在jQuery源代码的基础上修改来的-___-b,支持最基本的需求。这个页面可以设置很长的过期头让浏览器缓存起来,因为不会再有变动。

在父页面里通过TUI.videoComment.request提供统一的接口,不做详述了,只列举其中访问跨域方法的部分:

1.(function(){
2.    try{
3.        $('#crossdomain')[0].contentWindow.TUI.ajax(o);   
4.    }catch(e){
5.        setTimeout(arguments.callee,500);
6.        return;
7.    }   
8.})();
七、总结一下
iframe适用于 ( 跨域的 && ( 返回大量数据 || 返回HTML内容 || 需要发POST请求 ) ) 的场合,除此之外还有comet里的串流技术(streaming)——本文不涉及。使用时需要注意保持资源的纯粹性,并尽可能隐藏那些跟其他异步请求差异很大的或包含hack的细节(比如嵌入iframe,触发回调函数,处理数据),设计出一致的,兼容性和扩展性良好的,不碍眼的接口XD

关于跨域还要补充一点:修改document.domain可能会产生一些无法预料的问题,比如在firefox里,document.styleSheets的cssRules属性会被拒绝访问。
分享到:
评论

相关推荐

    ajax跨域请求WebService.asmx

    【Ajax跨域请求WebService.asmx】是一个常见的Web开发技术应用场景,主要涉及到JavaScript的Ajax技术、C#编程语言以及ASP.NET的WebService组件。Ajax(Asynchronous JavaScript and XML)是一种在不刷新整个页面的...

    html通过 ajax jsonp跨域请求接收和传送数据

    HTML通过AJAX和JSONP跨域请求常用于获取远程API数据、实时更新网页内容、用户认证等场景。例如,社交网站获取用户信息、新闻网站动态加载评论、电子商务网站实时显示库存等。 综上所述,HTML借助AJAX和JSONP,可以...

    ajax跨域请求demo.zip

    这个"ajax跨域请求demo.zip"压缩包提供了一个关于如何实现Ajax跨域请求的示例,涉及到前后端的交互。 首先,我们关注"前端代码"部分。前端通常使用JavaScript库如jQuery来实现Ajax请求。jQuery的`$.ajax()`方法是...

    解决ajax跨域请求问题

    然而,跨域请求是Ajax的一个常见问题,由于浏览器的同源策略限制,Ajax请求只能向与当前页面同源的服务器发送。本文将深入探讨如何解决Ajax跨域请求的问题。 首先,理解“同源策略”是解决问题的关键。同源策略是...

    详解Vuejs2.0之异步跨域请求

    在本文中,主要讨论了Vuejs2.0环境下如何处理异步跨域请求。Vuejs是现代前端开发中使用极为广泛的一个JavaScript框架,其2.0版本相较于1.0版本有了较大的变化。其中,HTTP请求的推荐方式也发生了改变,不再推荐使用...

    Ajax异步(请求)提交类 支持跨域

    - **本例中的解决方式**:本例中的异步请求类采用了代理服务器的方式,通过一个中间脚本(如`/geturl.aspx`)作为代理,将跨域请求转发给目标服务器。 ##### 4. 代码解析 - **异步请求类**:该类提供了基本的异步...

    ajax处理跨域请求

    然而,随着互联网应用的发展,数据交互的需求日益增多,跨域请求成为一种常见的需求。AJAX(Asynchronous JavaScript and XML)技术允许我们在后台与服务器进行异步数据交换,而无需刷新整个页面。当使用AJAX进行...

    解决 springboot跨域请求问题

    SpringBoot应用可以通过配置CORS来允许特定或所有来源的跨域请求。在SpringBoot应用中,你可以创建一个配置类,比如`CorsConfig`,并添加一个`CorsFilter`。在`buildConfig`方法中,设置`CorsConfiguration`对象,...

    异步 提交表单请求

    为了实现跨域请求,可以使用CORS(跨源资源共享)机制,在后端设置合适的Access-Control-Allow-*响应头。 6. **异步请求的优点与挑战** 优点包括改善用户体验、提高性能和减少服务器压力。但异步请求也可能带来...

    跨域请求解决方案

    跨域请求是Web开发中一个常见的挑战,尤其是在使用Ajax进行异步数据交互时。这个问题源自浏览器的同源策略,该策略限制了JavaScript只能访问与当前页面同源(协议、域名和端口相同)的资源。当尝试从一个域向另一个...

    Ajax异步请求

    但是,需要注意异步请求的限制和安全问题,例如,避免cross-site scripting(XSS)攻击和跨域请求问题。 Ajax异步请求的优点包括: * 提高用户体验和页面加载速度 * 实现异步通信,提高应用程序的响应速度 * 减少...

    jquery下异步提交表单 异步跨域提交表单

    可以创建一个同域的中间服务器,用来接收来自客户端的跨域请求,然后由这个中间服务器向实际的目标服务器发起请求,再将响应结果返回给客户端。这种做法的实质是将跨域请求转化为同域请求。 #### 使用CORS 虽然...

    Ajax异步请求的验证

    默认情况下,浏览器禁止了Ajax的跨域请求,但可以通过CORS(Cross-Origin Resource Sharing)策略解决。服务器端需要设置适当的响应头,如`Access-Control-Allow-Origin`,允许特定域名进行跨域请求。 六、同步与...

    javascript跨域请求包装函数与用法示例.docx

    - **AJAX**(Asynchronous JavaScript and XML)是一种用于创建动态网页的技术,但默认情况下不支持跨域请求。 #### 三、示例代码解析 ##### 3.1 定义跨域请求函数 `$JSON._ajax` 该函数接受一个配置对象作为参数...

    ajax 跨域请求问题 jquery jsonp

    **Ajax跨域请求问题与jQuery JSONP解析** 在Web开发中,Ajax技术被广泛用于实现页面的异步更新,但浏览器的同源策略(Same-Origin Policy)限制了Ajax请求只能向同源(协议、域名、端口均相同)的服务器发送。这在...

    ajax跨域请求

    **Ajax跨域请求详解** Ajax(Asynchronous JavaScript and XML)技术是现代Web开发中的关键组成部分,它允许在不刷新整个页面的情况下与服务器进行异步数据交换。在处理跨域请求时,Ajax扮演着至关重要的角色。跨域...

    ajax跨域请求调用webservice接口+视频教程

    【标题】"Ajax跨域请求调用WebService接口"是一个关键的技术点,主要涉及到Web开发中的异步数据交互和跨域安全策略。在Web应用程序中,Ajax(Asynchronous JavaScript and XML)技术允许我们在不刷新整个页面的情况...

    Ajax 跨域异步传输

    JSONP的工作原理是利用 `&lt;script&gt;` 标签不受同源策略限制的特点,通过动态创建 `&lt;script&gt;` 元素并指定其 `src` 属性为跨域请求的URL,该URL包含一个回调函数名作为参数。服务器接收到请求后,将返回的JSON数据包裹在...

    Python Tornado之跨域请求与Options请求方式

    在前后端分离的开发模式下,Tornado作为后端服务,需要处理来自不同源的跨域请求,这涉及到浏览器的同源策略和CORS(Cross-Origin Resource Sharing)机制。 跨域请求是指前端应用(如Vue)尝试从不同的源(域名、...

Global site tag (gtag.js) - Google Analytics