注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

obsolete

wanna go

 
 
 

日志

 
 

AJAX跨域获取数据  

2012-04-23 21:38:29|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
ajax可以在不刷新页面的情况下,获取服务器端数据。不过由于各浏览器的安全限制,ajax很可能不允许跨域访问(这类限制是必要的,如果不加任何限制,ajax可以通过"file://xxx"获取本地主机的一些重要信息并发送往服务器,造成安全隐患)。
但有的时候,位于a域(假设域名为a.com)的页面确实需要访问b域(假设域名为b.com)并获取一些数据,有没有办法实现这样的需求呢?
传统的方式是在a域的服务器端处理,即客户端访问a.com的一个页面,a.com在服务器端通过http协议访问b域,获取数据后返回给客户端。相当于a.com服务器充当了代理。
这种方式的缺点是,每次访问a.com的这个页面,都会造成整页刷新。下面的场景不太好处理:b.com对请求的处理比较耗时,它允许客户(这里的客户包 括a.com和浏览器客户端等)的请求立即返回,但后续需要不断轮询以查询处理进度。由于B-S架构不支持服务器端主动向客户端发消息,使用ajax轮询 来模拟这种行为是很常见的。如果采用刚才提到的方法(a.com服务器做代理),每次轮询都造成整页刷新,用户体验不好。最好的解决方案还是在ajax中 直接访问b.com。

ajax不能跨域访问,也就是说,a.com服务器生成的页面,不能通过ajax直接访问b.com的资源。有一种巧妙的办法绕过这种安全机制:

我们注意到,HTML的script标签,src属性可以跨域制定js文件的来源,即下面的代码是合法的

  1. <script src="http://b.com/xxx.js"></script>  
这段代码即使放到a.com生成的页面中,也能正确的加载到b.com中的js文件,并执行里面的代码。
如果a.com和b.com的开发者可以相互交流,或是b.com明确支持下面提到的约定,ajax可以通过这样的机制,获取b.com上的数据(这些限制使得下面的方式不被视为一种严重的安全漏洞)。具体做法是:
  1. a.com的页面动态生成一个script元素,src属性设置为b.com上获取数据的url,比如是http://b.com /xxx?xxx,同时,在这个资源url最后加上一个特殊的参数,变成http://b.com/xxx?xxx&callback=fun。 注意,这里的callback是个约定名称(在b.com的服务器端要特别处理callback名字的参数)。也就是说,a.com的页面中可以将这个参 数名改成mycallback等任意的名字,但必须告诉b.com这个名字到底是什么。callback的值"fun"是一个a.com页面上实现的函数 的函数名。
  2. script允许跨域访问,a.com会向b.com申请这个url对应的js文件(代码)。b.com拿到这个url,取出callback参数,获得"fun"这个字符串。
  3. b.com 动态生成js文件(代码),其中插入一段代码"fun(...)"。参数通常是一个JSON对象(这是惯例,a.com和b.com也可以协定别的参数类 型),比如"fun({p1:1,p2:2})"。b.com将包含这句代码的js文件(代码)发送给a.com。
  4. a.com的 script标签获取到来自b.com的js文件(代码)后,立即执行,这时,会执行到"fun({p1:1,p2:2})"这句代码。注意到fun是 a.com页面中的一个函数,则这里是个函数调用。此时a.com的fun函数就可以接收到b.com传过来的JSON对象({p1:1,p2:2}) 了。


JQuery也是使用类似的机制实现的JSONP,一个例子如下,客户端

[javascript] view plaincopy
  1. $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=cat&tagmode=any&format=json&jsoncallback=?",  
  2.     function(data){  
  3.       $.each(data, function(i,item){  
  4.         $("p").append(i+": "+item+"<br>");  
  5.       });  
  6.     }  
  7. );  
注意这里调用的url中包含"jsoncallback=?","?"会被JQuery替换成实际的回调函数名,用户(网页编写者)不用关心。跨域服务器响应时,JQuery保证能调用到用户编写的匿名函数(例子中$.getJSON()的第二个参数)。
服务器端如果是JSP,代码大致如下
  1. ...  
  2. String jsoncallback=request.getParameter("jsoncallback");  
  3. ...  
  4. PrintWriter out = response.getWriter();  
  5. out.print(jsoncallback+"({\"account\":\"XX\",\"passed\":\"true\",\"error\":\"null\"})");  
Jquery取得的数据可能如下
[javascript] view plaincopy
  1. JQUET0988788({"account":"XX","passed":"true","error":"null"})  

JQUET0988788调用会调用到用户自己编写的匿名函数。

[小贴士]

IE内核的浏览器在使用script.src方式请求资源时,request不会携带sessionid信息,对于服务器端而言,每次请求都来自不 同的客户端,则在ajax轮询的场景里,服务器端可能无法准确判断客户端的身份而导致需求难以实现。FireFox、Chrome等浏览器没有这样的问题 (它们的请求可以携带sessionid)。

解决办法是:客户端在script.src的请求url中加入特殊的参数以携带sessionid(类似上面的callback参数,与b.com 做好约定),如果客户端还未获取sessionid,这个参数可以不指定;服务器获取这个sessionid,通过它来判断客户端的身份,如果url中没 有指定,则使用当前自动生成的sessionid(request.getSession().getId()),并把它加入返回的json对象的某个字 段中;客户端获取这个字段的值,并把它加入下次请求的url中。
  评论这张
 
阅读(1032)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018