用dojo.io.script跨域
dojo.xhr* 只是XmlHttpRequest对象的封装,由于同源策略限制,它不能发跨域请求,要跨域还是需要动态创建<script>标签。Dojo 没有像JQuery一样把所有东西都封装在一起(JQuery的ajax()方法可以跨域,当然用的是JSONP,所以它不敢把自己称为xhr),而是坚持一个API只干一件事情。毕竟在大部分应用中,同域请求比跨域请求多得多,如果一个应用不需要跨域,就没必要加载相关代码。因此与xhr不同,dojo 的跨域请求组件不在基本库,而在核心库,需要require一下才能使用:
- dojo.require("dojo.io.script");
这个包里面基本上只需要用到一个函数:dojo.io.script.get()。它也返回Deferred对象,并接受类型为 dojo.io.script.__ioArgs的散列参数。受益于虚拟参数类,我们不用从头开始学习这个参数,它继承了dojo.__IoArgs,因此和dojo.xhr*系列的参数大同小异。唯一需要注意的是handleAs在这里无效了,代之以jsonp或者checkString。
广州网站建设,网站建设,广州网页设计,广州网站设计
前者用于实现JSONP协议,其值由服务器端指定,当script标签加载后就按照JSONP协议执行这个函数,然后Dojo会自动介入,负责把真正的数据传给load函数。需要指出的是在Dojo1.4以前,这个参数叫callbackParamName,冗长但意义明确。毕竟Dojo太早了,它成型的时候(2005)JSONP这个词才刚出现不久。现在callbackParamName还是可用的(为了向后兼容),不过处于deprecated状态。
下面的例子从flickr获取feed数据:
- dojo.io.script.get({
- url: "http://www.flickr.com/services/feeds/photos_public.gne",
- jsonp: "jsoncallback", //由flickr指定
- content: {format: "json"},
- load: function(response){
- console.log(response);
- return response;
- },
- error: function(response){
- console.log(response);
- return response;
- }
- });
与jsonp不同,checkString参数专门用于跨域获取javascript代码,它其实是那段跨域脚本里的一个有定义的变量的名字,Dojo会用它来判断跨域代码是否加载完毕,配合前面提到的timeout机制就能实现有效的超时处理。
- dojo.io.script.get({
- url: "http://......", //某个提供脚本的URL
- checkString: "obj",
- load: function(response){
- //脚本加载完毕,可以直接使用其中的对象了,如obj。
- Return response;
- }
- });
用dojo.io.iframe传数据
dojo.io 包里还有一个工具就是iframe,常用于以不刷新页面的方式上传或下载文件。这个很经典的Ajax技巧在Dojo里就是一句 dojo.io.iframe.send({...})。这个函数接受dojo.io.iframe.__ioArgs,相比 dojo.__IoArgs,它只多了一个method参数,用于指定是用GET还是POST(默认)方法发送请求。下面的例子就实现了通过无刷新提交表单来上传文件:
- dojo.io.iframe.send({
- form: "formNodeId", //某个form元素包含本地文件路径
- handleAs: "html", //服务器将返回html页面
- load: onSubmitted, //提交成功
- error: onSubmitError //提交失败
- });
目前send函数的handleAs参数支持html, xml, text, json, 和javascript五种响应格式。除了html和xml之外,使用其他格式有一个比较特别的要求,就是服务端返回的响应必须具有以下格式:
广州网站建设,网站建设,广州网页设计,广州网站设计
- <html>
- <head></head>
- <body>
- <textarea>真正的响应内容</textarea>
- </body>
- </html>
这是因为服务器返回的东西是加载在iframe里的,而只有html页面才能在任何浏览器里保证成功加载(有个DOM在,以后取数据也方便)。加一个<textarea>则可以尽量忠实于原始文本数据的格式,而不会受到html的影响。
试试RPC(远程过程调用)
如果dojo.xhr*函数以及Deferred机制仍然无法避免代码的混乱,那RPC可能就是唯一的选择了。dojo.rpc包提供了基于“简单方法描述”语言(SMD)的RPC实现。SMD的原理类似于WSDL(Web服务描述语言),不过是基于JSON的,它定义了远程方法的名称、参数等属性,让 Dojo能创建出代理方法以供调用。
Dojo提供了两种方式实现rpc:XHR和JSONP,分别对应dojo.rpc.JsonService类和dojo.rpc.JsonpService类,用户可以根据是否需要跨域各取所需。
一个简单的例子:
- var smdObj = {
- serviceType: "JSON-RPC",
- serviceURL: "http://...."
- methods: [
- {name: "myFunc", parameters: []}
- ]
- };
- var rpc = new dojo.rpc.JsonpService(smdObj); //传入SMD
- var result = rpc.myFunc(); //直接调用远程方法,返回Deferred对象
- dojo.when(result, function(result){
- //得到结果
- });
SMD还没有一个被广泛认可的官方标准,一直以来都是Dojo社区领导着它的发展,以后这个模块也有可能发生改变,但整个RPC基本的框架会保持稳定。
结语
Ajax请求这个主题太大,本文只能挂一漏万地介绍一点dojo在这方面设计和实现的皮毛,包括基本XHR请求、动态script、iframe请求、以及RPC,并特别强调了几个有Dojo特色的设计,如timeout机制、虚拟参数类、Deferred对象等。
Dojo由Ajax领域的先驱们写就,相信从它的代码中我们一定能学到更多的东西。



