因为参加春招面试,一面被问到跨域的问题,当时一脸懵,之后了解了之后知道jsonp是一个比较典型的跨域方法,但是看了很多博客和讲解并不是很能理解,所以根据自己所看的简单总结。
一、JSONP产生的过程
1、众所周知,ajax需要满足同源策略,所以直接请求存在跨域问题的一切文件,都会报错。
2、但是当我们在编写html页面时,会发现有些特殊标签不受跨域的影响,比如:调用js文件和拥有src属性的标签(<\img><\script><\link><\iframe>等)。
3、于是可以判断,当前阶段想要通过web页面跨域访问就只有一个可能,就是在远程服务器上设法将数据装入js文件里,供客户端调用和进一步处理。
4、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们称作JSONP,**该协议的一个要点就是允许用户传递一个callback参数给服务器端,然后服务器端返回数据时会将这个callback参数作为函数名来包裹住的JSON数据,**这样客户端就可以随意搭建自己的函数来处理返回数据了。
二、JSONP的实现
1、我们知道,跨域js文件中的代码,web页面可以无条件执行,
2、当在jsonp.html页面定义一个函数,然后在远程remote.js传入数据进行调用。
jsonp.html代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>
</body>
</html>
remote.js文件代码如下:
localHandler({"result":"我是远程js带来的数据"});
3、上面跨域存在一个问题,就是当jsonp的服务器面对很多服务对象,这些服务对象的本地函数都不相同,怎样来确定当前调用的是哪个函数呢?
解决方法就是动态生成js脚本,可以传递一个参数告诉服务器:“我需要xxx函数的js代码,请返回给我。”,于是服务器可以按要求生成js脚本并响应了。
jsonp.html代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html
此处的callback参数告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
4、最后,jsonp的实现原理基本梳理结束,剩下的就是利用ajax进行封装,以便于与用户界面交互,从而实现多次和重复调用。
jQuery如何实现jsonp:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript" src=jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>
jQuery在处理jsonp类型的ajax时,自动帮你生成回调函数并把数据取出来供success属性方法调用。上面可以看出将jsonp归入ajax进行调用也实现了跨域请求,是不是可以说明ajax和jsonp是一回事?答案是否定的。
ajax和jsonp的异同:
(1)ajax和jsonp这两种技术在调用方式上看起来很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jQuery和ext等框架都把jsonp作为ajax的一种形式进行了封装。
(2)但是ajax和jsonp其实本质上是不同的东西,ajax的核心是通过XMLHttpRequest获取非本页内容,而jsonp的核心则是动态添加。