锁定老帖子 主题:javascript的跨域请求
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (12)
|
|||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||||||||||||||||||||||||||
发表时间:2011-01-05
最后修改:2011-01-12
话说上个世纪60年代初,在美国加州的森尼维尔市,伴着他的第一声哭声,Brendan Eich开始了他的一生。和普通的孩子一样,他度过了快乐的童年,懵懂的青年时代,也顺利的读完了学士和硕士学位,开始了他程序员的生活。 毕业以后他在Silicon Graphics玩了7年的操作系统和网络编程(难道一个人公司的感情也会有7年之痒)。 离开了他的老东家之后,他来到了MicroUnity Systems Engineering,玩起了microkernel和DSP编程,也是在这时他第一次接触了MIPS架构的gcc R4000端口。 他在Netscape和Mozilla的时候达到了事业上巅峰。1995年4月,他开始玩起了Mocha,经过他一段时间的努力Mocha变得很强大了,于是在同年的9月,一个华丽的变身,更名为livescript并且第一次被装在Netscape Navigator 2.0里。在同年的12月4日,在与Sun公司的的联合声明中,livescript变身到最终形态,JavaScript神兵横空出世。 由于JavaScript神兵太过强大,人们给他加了封印。可是人总是有私心的,于是又留下了一些打开封印的办法。 淡扯完了,下面介绍下封印和如何解开封印。 Same origin policy 先说下封印跨域访问,javascript同源策略的限制,即a.com域名下的js无法操作b.com域名下的对象(跨域)。下面举了几个例子,看起来更形象一些。
如果对Same origin policy还有什么不了解的可以到http://en.wikipedia.org/wiki/Same_origin_policy看下。 下面说下解开跨域访问这个封印的几个主要手印。 手印一JSONP,即JSON with Padding。由于封印同源策略的限制,跨域访问被封印了起来。如果需要解开封印进行跨域请求,得使用html的script标记,进行跨域请求,在response中,返回要执行的javascript代码、JSON对象等。这种解开封印进行跨域请求的方式称为JSONP。 如在www.a.com域名下有如下的html文件: <html> <head> </head> <body> <script type="text/javascript" id="script1"></script> <input type="text" id="a" name="a"> <input type="button" value="click" onclick="document.getElementById('script1').src='http://www.b.com/response.js'"> </body> </html> 在www.b.com下的响应的response.js代码 var a=1;//设置变量 alert("Hello World");//调用函数 document.getElementById("a").value="Hello World";//设置表单 大多数时候,为了动态,我们是这么玩的。把www.a.com下的htm改成 <html> <head> </head> <body> <script type="text/javascript" id="script1"></script> <input type="text" id="a" name="a"> <input type="button" value="click" onclick="document.getElementById('script1').src='http://www.b.com/response.jsp'"> </body> </html> 把www.b.com/response.js改成response.jsp <%out.print("var a=1;alert(\"Hello World\");document.getElementById(\"a\").value=\"Hello World\"");%> 虽然URL上看只多了一个p,但是手印JSONP却在解开封印的同时变得更具破坏力。 在手印JSONP的基础上,仙人YUI、Jquery、Dojo、Ext等纷纷研究出了自己的手印。
首先我们看看仙人YUI做了哪些工作。 YUI3.2的jsonp的使用方法如下(下面都是围绕YUI3.2分析的): var url = "http://yuilibrary.com/gallery/api/random?callback={callback}"; function handleJSONP(response){//...}; //... Y.jsonp(url,handleJSONP); //... ps:源码中examples/jsonp/jsonp_gallery.html有详细内容。 结印很快,调用很方便,下面看看是怎么实现的。 下载http://developer.yahoo.com/yui/3/,选择Full Developer Kit版,将yui_3.2.0.zip解压后,在yui/buil/jsonp目录下会看到6个文件:
主要看下jonp.js这个文件,在第8行 YUI.add('jsonp', function(Y) { //... 为YUI这个function动态添加了一个叫jsonp的function。后面的代码中用到了大家耳熟能详的prototype,apply和unshift等JavaScript神兵的秘法,就不一一分析了,直接看第133行到137行之间的代码。 //... Y.Get.script(url, { onFailure: wrap(config.on.failure), onTimeout: wrap(config.on.timeout), timeout : config.timeout }); //... 这里有个Y.Get.script(...)的调用,有url,onFailure,onTimeout和timeout参数,这个到底是做什么的呢? 看下yui/build/yui/get.js这个文件。 第30行到726行在做了一次漂亮的闭包的同时,给Y.Get赋了值。看下505行到725行,就会发现Y.Get大概长成这个样子 { PURGE_THRESH:20, _finalize:function(id){ ... }, abort: function(o) { ... }, script: function(url, opts) { return _queue("script", url, opts); }, css: function(url, opts) { ... } } 终于找到了上面提到的Y.Get.script这个function,可却发现里面另有洞天,还有个_queur(...)的调用,不入虎穴不得虎子,看看这个叫_queue的funciton里面到底有神马浮云。 跳到362行,找到了_queue的实现。不过别急,先看看上边353到361的注释 /** * Saves the state for the request and begins loading * the requested urls * @method queue * @param type {string} the type of node to insert * @param url {string} the url to load * @param opts the hash of options for this request * @private */ 说_queue对request的状态做了保存,而且开始load。好看代码吧。372行到378行和第389行的代码: //... queues[id] = Y.merge(opts, {//这个merge的实现也很精彩的,在yui/build/yui/yui.js中。 tId: id, type: type, url: url, finished: false, nodes: [] }); //... _next(id); //... 发现实现了保存request的状态,也同时看出这里没有实现load的而是在第389行多了个_next(id)的调用。这个_next(...)到底是干什么的呢?(这个_next才是主角,要详细的分析分析) //... d = w.document; h = d.getElementsByTagName("head")[0]; //... if (q.timeout) { // q.timer = L.later(q.timeout, q, _timeout, id); q.timer = setTimeout(function() { _timeout(id); }, q.timeout); } //... n = _scriptNode(url, w, q.attributes); //... if (insertBefore) { //... } else { h.appendChild(n); } //... 首先取document,然后领h只想head标签,n是通过_scriptNode再到_node,返回一个document.createElement("script"),在_node中通过一个漂亮的for(i in attr){ ... }循环完成了属性绑定。最后,如果没有指定insertBefore元素,那么就在head标签里,把上边创建的script标签append进去。 至此,仙人YUI的JSONP实现分析完毕。下面将要分析的是仙人Jqurey是怎么实现JSONP的。
登录http://jquery.com/,选择DEVELOPMENT (179KB, Uncompressed Code)下载源码,这个看着比PRODUCTION (26KB, Minified and Gzipped)的要舒服些。 先看看在Jquery下JSONP怎么使用。往上的例子大多是用$.getJSON,而且介绍的很好。JE上有好多牛人写了具体的分析和实现过程。再写一个有人会审美疲劳,所以下面的例子用的是更为强悍的$.ajax({dataType:'script'...})。因为它加载的是一段script代码,而不仅仅是一个json。下面看看是怎么用的。 $.ajax({ url: "http://2520011.appspot.com/js/cross_domain_demo.js",//为了这个例子在GAE放了个测试的js dataType: 'script', success: function(data ){ alert(data); } }); 接口的api设计的也很方便,下面看看他是怎么实现的。 在源码5762行,我们找到了ajax的实现。跳过中间层层叠叠的无关代码,来到5859行,在这里柳暗花明了,我们终于找到了渴求已久的源码。 var head = document.getElementsByTagName("head")[0] || document.documentElement; var script = document.createElement("script"); //... script.src = s.url; //... head.insertBefore( script, head.firstChild ); 算上插入就4行。。。Jquery真的够精简。牛人一般都这样吧,O(∩_∩)O哈哈~ 到这里我们分析玩了仙人Jquery的实现,真的是一个比一个牛,下一段,我们一起分析下Dojo的实现。 to be continued...... ps:周一到周五每天至少一更,周末休息。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-05
这种方式有一个更专业的叫法:jsonp
|
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-05
qgymje 写道 这种方式有一个更专业的叫法:jsonp
大名叫JSON with Padding。 代码行数上比写个AJAX的实现要简单很多。而且是天生的异步。 |
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
看不懂,咋跨域了
|
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
几个跨域的比较不错的实现方案 (Dojo)
1. dojo/io/script 2. dojox/io/windowName |
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
document.all 就是跨域? 也没有考虑浏览器兼容问题
|
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
引用 JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。 JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。 LZ可以看看这篇文章:http://kjah.iteye.com/blog/771797 |
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
通常采用iframe的方式来解决跨域问题
|
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
哈哈,谢谢大家提的宝贵意见。
本贴旨在重温一下JSONP跨域访问方式。 也希望大家多多提出自己的宝贵建议和经验。 谢谢大家回帖。 |
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||
发表时间:2011-01-06
extjs也封装了跨域访问,示例:
proxy: new Ext.data.ScriptTagProxy({ url: 'http://extjs.com/forum/topics-remote.php' }) |
|||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||