Ajax跨域的解决方案有2种:CORS、JSONP。下面一一来介绍。
1、CORS
CrossOrigin Resource Sharing跨域资源共享。
当前几乎所有的浏览器(Internet Explorer 8+,Firefox 3.5+,Safari 4+和Chrome)都可通过名为跨域资源共享(Cross-Origin Resource Sharing)的协议支持ajax跨域调用。
对一个简单的请求,没有自定义头部,要么使用GET,要么使用POST,它的主体是text/plain,请求用一个名叫Origin的额外的头部发送。Origin头部包含请求页面的头部(协议,域名,端口),这样服务器可以很容易的决定它是否应该提供响应。
服务器端:JSP页面中设置response.addHeader("Access-Control-Allow-Origin", "http://www.yoursite.com:8080")。
在请求信息中,浏览器使用 Origin 这个 HTTP 头来标识该请求来自于 http://www.yoursite.com:8080(发出跨区请求的url)。
在返回的响应信息中,使用 Access-Control-Allow-Origin 头来控制哪些域名的脚本可以访问该资源。
如果设置 Access-Control-Allow-Origin为*,则允许所有域名的脚本访问该资源。如果有多个,则只需要使用逗号分隔开即可。
2、JSONP
JSONP是JSON with Padding的略称,是一个非官方的协议,允许在服务器端集成Script tags返回至客户端,通过JavaScript callback的形式实现跨域访问。
JSONP比JSON外面有多了一层,callback()。也就是说,在服务器端需要先将查询结果转换成JSON格式,然后用参数callback在JSON外面再套一层,就变成了JSONP。
JSON格式:
{
"message":"获取成功",
"state":"1"
}
JSONP格式:
callback({
"message":"获取成功",
"state":"1"
})
(1)JavaScript与JSONP
JSONP的简单实现模式:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
http://www.msnova.net/a.html
<script type="text/javascript">
function callback(data) {
alert(data.message);
}
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function(){
addScriptTag("http://blogs.msnova.net/b.js");
}
</script>
http://blogs.msnova.net/b.js
callback({message:"success"});
说明:
① 动态创建script:addScriptTag方法中的document.body.appendChild(script)实现script标签被添加到body里,由于我们JS代码是在head标签中,执行到document.body.appendChild(script)时document.body可能还没有初始化完毕,所以通过window.onload方法确保页面加载完毕再添加script标签。
② 实际上,<script>标签的src属性并不被同源策略所约束,所以可以获取任何服务器上脚本并执行,因此,以上实例并不能算是一个真正的JSONP跨域服务。下面是真正的JSONP跨域服务:
http://www.msnova.net/a.html
<script type="text/javascript">
function result(data) {
alert("Hello " + data.student[0].name);
}
function addScriptTag(src){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function(){
addScriptTag("http://blogs.msnova.net/dataProcessor?city=Beijing&callback=result");
}
</script>
服务器端http://blogs.msnova.net/dataProcessor会将查询结果转换成JSON格式,然后用参数callback在JSON外面再套一层变成JSONP作为响应返回,此处涉及到后台代码,不写出。
(2)jQuery与JSONP
jQuery框架也支持JSONP,可以使用$.getJSON(url,[data],[callback])方法和$.ajax()方法。
① $.getJSON方法:
<script type="text/javascript">
$.getJSON("http://blogs.msnova.net/dataProcessor?callback=?",function(data){
alert("Hello " + data.student[0].name);
});
</script>
注意:在url的后面必须添加一个callback参数,这样getJSON()方法才知道是用JSONP方式,callback后面的问号是内部自动生成的一个回调函数名。
② $.ajax()方法:
a. jsonp参数:
使用$.ajax形式可以不在url的后面添加一个callback参数,但此时需要指定jsonp参数。jsonp: “callback”代表的是服务端通过String callback = request.getParameter("callback") 接收客户端回调函数名的参数名,ajax请求中jsonp参数的默认值就是callback,也可以自己随便定义。
$.ajax({
url:"http://blogs.msnova.net/dataProcessor",
dataType:"jsonp",
jsonp:"callback",
success:function(data){
alert("Hello " + data.student[0].name);
}
});
等价于:
$.ajax({
url:"http://blogs.msnova.net/dataProcessor?callback=?",
dataType:"jsonp",
success:function(data){
alert("Hello " + data.student[0].name);
}
});
b. jsonpCallback参数:
jsonpCallback: “callbackHandler”代表的是服务端调用结束后的本地回调函数名,比如jsonp: “callback”中的客户端回调函数名,jsonpCallback的参数值也可以自己随便定义,也可以不给jsonpCallback参数,其实jQuery会自动生成一个函数和函数名,远程服务调用成功后,既执行了success这个回调函数,也执行自己定义的jsonpCallback指定的回调函数,所以完全可以使用jQuery生成的回调函数,在调用结束后在success回调中做相应的处理即可。
$.ajax({
url:"http://blogs.msnova.net/dataProcessor?callback=?",
dataType:"jsonp",
jsonpCallback:"result",
success:function(data){
alert("Hello " + data.student[0].name);
}
});
等价于:
$.ajax({
url:"http://blogs.msnova.net/dataProcessor",
dataType:"jsonp",
jsonp:"callback",
jsonpCallback:"result",
success:function(data){
alert("Hello " + data.student[0].name);
}
});
此处并没有定义result函数,也运行成功了。这是jQuery的功劳,jQuery在处理jsonp类型的ajax时,会自动生成回调函数并把数据取出来供success属性方法来调用。