环境描述
- 服务器:使用jersey提供RESTful接口
- 客户端:使用jquery的getJson()方法异步获取数据
- 希望实现的功能:服务器端以json格式提供RESTful的数据访问,客户端通过ajax异步加载的方式读取数据。
出问题代码
(其实下面代码也不包含错误,只是在执行的时候会出问题)
客户端原始代码:
document.getElementById("mydiv").innerHTML = "data";
$(function(){
$.getJSON("******", function (data) {
alert("go");
document.getElementById("mydiv").innerHTML = "hahahah";
});
});
服务器端原始代码:
@GET
@Path("/test")
@Produces("application/json;charset=utf8")
public String go(){
return "({\"num\":\"3\"}";
}
结果运行的时候就出问题了,客户端的回调函数死活不执行。用Firefox的Httpfox调试下,发现在获取json数据的时候就遇到问题,报错application/json (NS_ERROR_DOM_BAD_URI)
。
网上找了下,说是jquery跨域访问的安全问题,就是说:
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。但在安全限制的同时也给注入iframe或是ajax应用上带来了不少麻烦。首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。
上边的代码中,客户端和服务端确实在不同的服务器,使用不同的IP地址和端口号,因此出现了问题。
解决办法就是JSONP,全称是 JSON with Padding ,是基于 JSON 格式的为解决跨域请求资源而产生的解决方案。其基本原理是利用了 HTML 里 元素标签可以跨域访问,因此将数据封装成为js回调函数的格式进行传输访问。
举个例子,上述的数据{"num":"3"}
,这时不能跨域访问的,那么救把它包装为js,callback('{"num":"3"}')
,将数据包装为回调函数的参数,就可以跨域访问了。这就需要解决一个问题,提供数据访问的服务器必须进行数据封装的操作,如果响应的时候还是把原来的json格式数据输出,那么客户端是拿不到需要的数据的。
如果说服务器没有对数据进行封装,那么出现的问题就是回调函数死活不执行。即使用Httpfox进行调试,也会发现虽然正确访问了数据链接,服务器也返回了数据,但回调函数就是执行不了。就是因为这个问题困了我整整两天……
解决方案
其实jQuery已经封装了JSONP的使用
$.getJSON( "****?jsoncallback=?", function( data ){
// 处理跨域请求得到的数据
});
jquery会把jsoncallback
后边的?
替换为一个字符串作为数据访问的回调函数的函数名,在服务器端需要读取该参数,然后使用它对数据进行封装,也就是改成f(data)
的样式,加上函数名和括号就行了。
服务器端代码为:
@GET
@Path("/test")
@Produces("application/json;charset=utf8")
public String go(@QueryParam("jsoncallback") String jsoncallback){
System.out.println(jsoncallback);
String info = jsoncallback+"({\"num\":\"3\"})";
return info;
}
ok,再访问就没有问题了!
PS:最后吐槽一下网络上的各种解决方案,都是只给一个
jsoncallback
参数,服务器需要怎么改一点都不说,结果整整两天一直困在回调函数不执行的苦恼中……感谢基于JQuery、Jsonp与Jersey的跨域访问这篇文章替我找到了回家的路!