什么是JSONP?
首先提一下 JSON 这个概念,JSON 是一种轻量级的数据传输格式,被广泛应用于当前 Web 应用中。JSON 格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以 JSON 格式进行数据的传输。
JSON和JSONP虽然只有一个字母的差别,但其实他们根本不是一回事儿:JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。我们拿最近比较火的谍战片来打个比方,JSON是地下党们用来书写和交换情报的“暗号”,而JSONP则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传递双方约定的方法。
首先抛出浏览器同源策略这个概念,为了保证用户访问的安全,现代浏览器使用了同源策略,即不允许访问非同源的页面,详细的概念大家可以自行百度。这里大家只要知道,在ajax中,不允许请求非同源的URL就可以了,比如 www.a.com 下的一个页面,其中的ajax请求是不允许访问 www.b.com 中任何一个页面的。
1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;
2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如
JSONP原理
ajax 请求受同源策略影响,不允许进行跨域请求,而 script 标签 src 属性中的链接却可以访问跨域的js脚本,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
JSONP具体实现
1、首先看下ajax中如果进行跨域请求会如何。
前端代码在域 localhost 下面,使用 ajax 发送了一个跨域到 local.sns.jutouit.com 的 get 请求
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + " name:" + data.name + " sex:"+data.sex);
}
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type : "get",
async: false,
url : "http://local.sns.jutouit.com/radius.php?id=1",
type: "json",
success : function(data) {
jsonhandle(data);
}
});
});
</script>
</body>
</html>
意思就是无法请求到 local.sns.jutouit.com 的资源,原因就是禁止了跨域请求资源。
2、下面使用 JSONP,将前端代码中的 ajax 请求去掉,添加了一个script标签,标签的 src 指向了另一个域 local.sns.jutouit.com 下的 remote.js 脚本
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + " name:" + data.name + " sex:"+data.sex);
}
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
</script>
<script type="text/javascript" src="http://local.sns.jutouit.com/remote.js"></script>
</body>
</html>
这里调用了跨域的 remote.js 脚本,remote.js 代码如下:
jsonhandle({
"age" : 25,
"name": "Yibin",
"sex": "男"
});
这段远程的 js 代码执行了上面定义的函数,弹出了提示框如下:
3、这样就简单地解决了跨域获取数据的问题,但是 js 写死了,不够灵活,以下换成动态生成 html 元素并动态设置 js 的 src 属性等。
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + " name:" + data.name + " sex:"+data.sex);
}
</script>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var url = "http://local.sns.jutouit.com/test.php?id=1&callback=jsonhandle";
var obj = $('<script><\/script>');
obj.attr("src",url);
$("body").append(obj);
});
</script>
test.php 代码如下(更灵活的方法可以通过定义方法来获取指定数据,下面数据是写死的,测试方便而已。):
<?php
$data = array(
'age' => 24,
'name' => '小华',
'sex' => '女'
);
$callback = $_GET['callback'];
echo $callback."(".json_encode($data).")";
return;
意思同上一步是一样的,等价于 jsonhandle(array(…)); 也就是方法的定义。供前端页面调用。执行结果如下:
4、jQuery 提供了方便使用 JSONP 的方式,虽然类似 ajax 的请求,但是本质是不一样的,且只能使用 get 请求,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type : "get",
async: false,
url : "http://local.sns.jutouit.com/test.php?id=1",
dataType: "jsonp",
jsonp:"callback", //请求php的参数名
jsonpCallback: "jsonhandle",//要执行的回调函数(参数值)
success : function(data) {
alert("age:" + data.age + " name:" + data.name + " sex:"+data.sex);
}
});
});
</script>
</body>
</html>
test.php 代码跟上面的一样。效果图如下: