1、JSONP的诞生过程综述
1) Ajax无法跨域,引起了开发者的思考。
2) 开发者发现, <script>标签的src属性是可以跨域的,是否可以把跨域服务器写成调用本地的函数,回调数据回来?
3) JavaScript刚好支持JSON(object)。
4) 调用跨域服务器上动态生成的js格式文件(不管是什么样的跨域服务器,最终生成的返回值都是一段js代码)。
5) 这种获取远程数据的方式看起来非常像Ajax,但其实并不一样,逐渐形成了一种非正式传输协议,称作JSONP。
6) 传递一个callback参数给跨域服务器,然后跨域服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据进而返回。
2、JSONP的诞生过程细述
1) 哪怕跨域js文件中的代码,web页面也是可以无条件执行的。
远程服务器www.server.com根目录下的server.js文件:
alert(“我是跨域调用得到的响应”);
本地服务器www.client.com根目录下的client.html文件:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://www.server.com/server.js"></script>
</head>
<body>
</body>
</html>
跨域调用显然可以成功。
问题:跨域远程获取数据如何实现?
2) 在client.html页面定义一个函数,然后在server.js中传入数据进行调用。
远程服务器www.server.com根目录下的server.js文件:
serverResponse({"result":"我是跨域调用得到的响应"});
本地服务器www.client.com根目录下的client.html文件:
<!DOCTYPE html>
<html >
<head>
<title></title>
<script>
var serverResponse = function(data){
alert(“跨域调用得到的响应是:” + data.result);
};
</script>
<script src="http://www.server.com/server.js"></script>
</head>
<body>
</body>
</html>
跨域远程获取数据的目的实现。
问题:JSONP的服务器往往要面对很多客户端,而这些客户端各自的本地函数都不相同,如何让服务器知道它应该调用的本地函数是什么?
3) 服务器提供的JS脚本动态生成,客户端传递一个参数告诉服务器要查询的信息,服务器根据客户端的需求来动态生成JS脚本。
远程服务器www.server.com根目录下的getResult.jsp文件动态生成的JS脚本:
serverResponse({
"name":"Amy",
"age":23,
"school":"BUPT"
});
本地服务器www.client.com根目录下的client.html文件:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
var serverResponse = function(data){
alert("跨域调用得到的响应是:" + data.result);
};
var url = "http://www.server.com/getResult.jsp?name=Amy&callback=serverResponse";
var script = document.createElement('script');
script.setAttribute('src', url);
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>
问题:如何实现多次和重复调用?jQuery如何实现JSONP调用?
3、JSONP的基本原理
JSONP的最基本的原理是:动态添加一个<script>标签,而script标签的src属性是没有跨域的限制的。其实,JSONP跨域方式与Ajax XmlHttpRequest协议无关。
4、JSONP的执行过程:
1) 客户端注册一个callback (如:'jsoncallback'), 然后把callback的值(如'jsonpValue')传给服务器;
2) 服务端得到callback的数值后,要用jsonpValue(......)把将要输出的JSON内容包括起来,此时,服务器生成JSON数据才能被客户端正确接收。
3) 以JavaScript语法的方式,生成一个function,function 名字是传递上来的参数 'jsoncallback'的值'jsonpValue'.
4) 最后将JSON数据直接以参数的方式,放置到function中,生成了一段js格式文件,返回给客户端。
5) 客户端浏览器,解析script标签,并执行返回的js格式文件,此时js格式文件的数据作为参数,传入到了客户端预先定义好的callback函数(如$.ajax()方法封装的success: function(data)里。
5、jQuery用Ajax封装JSONP
远程服务器www.server.com根目录下的getResult.jsp文件动态生成的JS脚本:
serverResponse({
"name":"Amy",
"age":23,
"school":"BUPT"
});
本地服务器www.client.com根目录下的client.html文件:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src=jquery-1.8.2.min.js"></script>
<script>
$(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://www.server.com/getResult.jsp?name=Amy",
dataType: "jsonp",
jsonp: "callback",
jsonpCallback:"serverResponse",
success: function(data){
alert('年龄: ' + data.age + ',学校: ' + data.school);
},
error: function(){
alert(“跨域调用失败”);
}
});
});
</script>
</head>
<body>
</body>
</html>
6、Ajax和JSONP
Ajax和JSONP在调用方式上看起来很像,目的也都是请求一个url,然后把服务器返回的数据进行处理,因此jQuery把JSONP作为Ajax的一种形式进行了封装。
Ajax和JSONP本质上是不同的:Ajax的核心是通过XmlHttpRequest获取非本页内容,而JSONP的核心则是动态添加<script>标签来调用服务器提供的JS脚本。
Ajax和JSONP的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
7、JSONP的优缺点
(1)优点
① 不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
② 兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持。
③ JSONP在请求完毕后可以通过调用callback的方式回传结果,将回调方法的权限给了调用方,相当于将controller层和view层终于分开了。JSONP服务只提供纯服务的数据,至于提供服务以后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,只需要有不同的渲染逻辑就可以了,逻辑都可以使用同一个JSONP服务。
2)缺点
① 只支持GET请求而不支持POST等其它类型的HTTP请求;
② 只支持跨域HTTP请求,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
③ JSONP在调用失败时不会返回各种HTTP状态码。
④ 缺乏安全性。万一假如提供JSONP的服务存在页面注入漏洞,即它返回的JavaScript的内容被人控制的。那么所有调用这个JSONP的网站都会存在漏洞,于是无法把危险控制在一个域名下,所以在使用JSONP的时候必须要保证使用的JSONP服务必须是安全可信的。