原文链接:http://sonyfe25cp.iteye.com/blog/609725
------------------------------------------------------------------------------------------------------------------------------------
关于ajax跨域取数据,有很多解决办法。但多数都是具体情况具体对待,没有统一的完美解决方案。
本文包括两种ajax跨域的解决方案,第一种是用servlet屏蔽掉跨域,具体获取数据由servlet完成,ajax跟平时并无不同。第二种方式由jquery提供的jsonp来完成,内部原理是利用script标签的src无跨域限制来实现的,具体解释可以参看相关同类文章,后文只是对使用过程中发现的注意事项略作记述。
两种方案,servlet解决的比较好,但是略显笨重,耦合度稍高,jsonp比较轻易,但只支持get方式请求,部分情况下可能无法满足需求,而且不支持ajax的同步处理,即async:false属性对jsonp无效。
-------------------------------------------------------------------------------------------------------------------------------------
问题描述:
1.根据已知的url,获取url中的id,然后拼接出另一个url,去获取该id对应的值。
举例:
已知url:http://video.guoshi.com/play/index/4b6a3c233b4cb.html?peixun=1&start=680000
获取id 为:4b6a3c233b4cb
拼接的url:http://video.guoshi.com/rest-video?id=4b6a3c233b4cb
2.通过浏览器可以观察到上面url的内容是:
- <?xml version="1.0" encoding="utf-8" ?>
- lt;packet version="1.0.0">
- <status>success</status>
- <data>
- <item>
- <id>4b6a3c233b4cb</id>
- <count_view>43</count_view>
- <updated>2010-03-04 17:08:28</updated>
- </item>
- </data>
- </packet>
3.目标就是取到这个xml中的<count_view>43</count_view>的41
4.采用jQuery的ajax实现.
问题:这个url跟我的系统不是同一个域.涉及到了ajax的跨域问题.由于不能通过修改用户IE的 Internet选项-安全-自定义安全-跨域浏览资源 启用 ,所以这个问题就显得棘手了。
5.思路:
1)自己做一个servlet,让ajax访问自己的servlet来获取这个xml.
2)servlet接收id参数.然后输出对应的xml
3)servlet中采用java的HttpURLConnection来获取原地址的源代码,然后输出.
4)注意设置编码utf-8,类型text/xml
6.servlet:GetClickNum
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String id=request.getParameter("id");
- String url="http://video.guoshi.com/rest-video?id="+id;
- String curLine = "";
- String content = "";
- URL server=new URL(url);
- HttpURLConnection connection = (HttpURLConnection) server.openConnection();
- connection.connect();
- InputStream is = connection.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(is));
- while ((curLine = reader.readLine()) != null) {
- content = content + curLine + "";
- }
- is.close();
- response.setContentType("text/xml");
- response.setCharacterEncoding("utf-8");
- ServletOutputStream out = response.getOutputStream();
- out.print(content);
- }
这样原来的 http://video.guoshi.com/rest-video?id=4b6a3c233b4cb
就转换成 /GetClickNum?id=4b6a3c233b4cb
跨域问题解决!
7.js
- $('#rows').find('li').each(function(){
- var url=$(this).find('a[id=videoUrl]').attr('href');
- var b=url.lastIndexOf('index');
- var e=url.lastIndexOf('.');
- var id= url.substring(b+6,e); //the id
- var $li=$(this);
- $.ajax({
- type:"POST",
- url :"GetClickNum",
- data:"id="+id,
- timeout:10000,
- success : function(xml) {
- var val=$(xml).find("data>item>count_view").text();
- $li.find('b[id=click]').html("点击量:"+val);
- //alert(val);
- }
- });
- });
总结:
本文解决ajax跨域问题的思路就是将跨域变成不跨域.将对方服务器的servlet功能由自己的servlet来实现!
---------------------------------------------------------------------------------------------
在采用该方法的时候,遇到的一个问题是乱码。原因是BufferedReader默认采用iso-8859-1的编码方式进行读取数据,而如果发送端的编码不是该种编码(比如utf-8),那么便会产生乱码问题,解决办法是在创建这个reader的时候指定编码,方式是 BufferedReader reader = new BufferedReader(new InputStreamReader(is,"utf-8")); 还有一个问题是采用ServletOutputStream 进行输出数据时也报了一个异常,java.io.CharConversionException: Not an ISO 8859-1 character:也是默认编码的问题,正好是servlet,改成PrintWriter out = response.getWriter(); out.print(content);进行输出即可,当然别忘了关掉这个out流。
还有值得注意的是,这么输出的实际是一个文本类型也就是字符串,具体怎么处理就看js怎么写了。
ps:这么解决的好处是屏蔽了跨域,也无需考虑浏览器的差异。
/
以上内容为某位前辈所作,的确很好的解决了跨域问题。但该方法需在请求发起端写一servlet,获取数据由servlet来完成,显得有些麻烦。相对来说,jsonp不失为这一遗憾的一种补充。
jsonp是由jquery支持的一种“数据格式”,其实并不是数据格式,具体原理网上都有介绍,是在页面上利用script标签的src属性进行的,需要注意的是后台的数据返回处理跟同步问题,下面贴代码:
js部分:
$.ajax({
type:"GET",
url: "http://"+adServer+":"+port+"/ad/AD2.xhtml?action=show_ad",
data: "name="+panel_name+"&"+new Date(),
dataType: "jsonp",
cache:false,
success: function(ad_){
operate(ad_);//由于jsonp不支持ajax同步获取数据,故后续操作在此处理
},
error:function(data){
alert("error happened");
}
});
后台java部分:
public void show_ad(HttpServletRequest request,
HttpServletResponse response){
String callback = request.getParameter("callback");
PrintWriter out = null;
try {
out = response.getWriter();
out.print(callback+"("+JsonUtil.list2json(this.getAdService().show_ad((HashMap)this.getParams(request)))+");");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
out.flush();
out.close();
}
}
项目中的部分代码,可以运行,相关其它部分作省略处理。
**当时无意中发现该功能需要做跨域处理,由于之前用过servlet的那种处理方案,所以很想用那个,但有同事提出说jsonp可以跨域,于是按照资料进行模仿,结果每次都不成功,返回error,经查明为后台返回数据时不正确,跟正常情况略有不同,需加callback。
**另:由于当时js代码的结构设计,想先ajax在success获取到需要的数据data,然后将data赋值给某个局部变量,再return给外边的变量,但始终未成功。经排查为同步问题,查阅资料发现jsonp不支持同步设置,jquery源码这样解释:
async
Default: true
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false.Cross-domain requests anddataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active.
结束