1.什么是JSONP
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。JSONP并不是一种正式传输协议,允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
2.JSONP和AJAX
ajax和jsonp这两种技术在调用方式上”看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装。
但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加。
3.为什么Ajax不能跨域请求?
浏览器的同源策略,使得AJAX请求只能发给同源的网址,否则就报错。试想如果Ajax可以偷偷摸摸发请求,而不需要用户操作,用户不知情,那么问题就大了,如果你上了一个不安全的网站,这个网站Ajax偷偷发一个请求到你的网银网站(这里跨域了)拿到你的Cookie,把Cookie传到这个不安全的网站自己的服务器,那么你的网银就会被盗。所以浏览器不允许Ajax跨域。
AJAX请求:
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
<script>
$.ajax({
type:'get',
url:'http://www.softwhy.com/demo/JSON/php/antzone.php'
});
</script>
</head>
<body>
<div id="thediv"></div>
</body>
</html>
将这段代码复制之后在浏览器运行,会出现跨域问题,截图如下:
4.JSONP的实现
Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>)
我们希望获取跨域服务器上获取xml文件上的如下数据,并且显示在指定的div中,xml文件内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
<book>
<range>前端专区</range>
<author>蚂蚁部落</author>
<target>css教程</target>
</book>
<book>
<range>前端专区</range>
<author>蚂蚁部落</author>
<target>div教程</target>
</book>
<book>
<range>资源专区</range>
<author>softwhy.com</author>
<target>特效下载</target>
</book>
<book>
<range>前端专区</range>
<author>softwhy.com</author>
<target>教程下载</target>
</book>
</bookstore>
很明显不能使用ajax跨域请求此xml文件,然后进行处理。
那么JSONP就要出场了,首先通过后台语言将上面的XML文件内容转换为JSON格式,看如下代码:
<?php
$path=$_SERVER["DOCUMENT_ROOT"].'/demo/JSON/XML/XML.xml';
$json=json_encode(simplexml_load_file($path));
?>
转换结果如下:
上面的unicode字符是将中文进行了转码,可以防止出现乱码的情况。
然后在客户端我们需要动态的创建一个<script>
标签,然后再进行请求以便实现跨域效果:
function getBooks(){
var script=document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src','http://www.softwhy.com/demo/JSON/PHP/antzone.php?callback=Books');
document.body.appendChild(script);
}
上面的代码动态创建了一个script标签,然后设置标签的src属性值,这个属性值最关键的地方是传送一个函数的名称,这个名称会在php后台经过处理包装后,作为一个函数调用的形式返回,函数的参数就是转换后的json格式数据,后台转换代码:
<?php
$path=$_SERVER["DOCUMENT_ROOT"].'/demo/JSON/XML/XML.xml';
$json=json_encode(simplexml_load_file($path));
$callbackFn=$_GET['callback'];
echo "$callbackFn($json);";
?>
完整前台代码实例:
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<script>
function books(books){
var books=books.book;
var booksContainer=document.getElementById('books');
var str="";
for(var index=0;index<books.length;index++){
str=str+"<div>"+
books[index]["range"]+","+
books[index]["author"]+","+
books[index]["target"]+
"</div>";
}
booksContainer.innerHTML=str
}
function getBooks(){
var script=document.createElement('script');
script.setAttribute('type','text/javascript');
script.setAttribute('src','http://www.softwhy.com/demo/JSON/php/antzone.php?callback=books');
document.body.appendChild(script);
}
window.onload=function(){
getBooks();
}
</script>
</head>
<body>
<div id="books"></div>
</body>
</html>
4.JSONP的封装
代码封装一下,以便于与用户界面交互,从而实现多次和重复调用,这里使用jQuery实现jsonp调用
jquery在处理jsonp类型的ajax时,自动帮你生成回调函数并把数据取出来供success属性方法来调用
$.ajax的参数:
- type:请求方式 GET/POST
- url:请求地址
- async:布尔类型,默认为true 表示请求是否为异步,如果为false表示为同步。
- dataType:返回的数据类型
- jsonp:传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
- jsonpCallback:自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
- success:调用成功执行的函数
- error:异常处理函数
<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<script type="text/javascript">
jQuery(document).ready(function () {
function books(books) {
var books = books.book;
var booksContainer = document.getElementById('books');
var str = "";
for (var index = 0; index < books.length; index++) {
str = str + "<div>" +
books[index]["range"] + "," +
books[index]["author"] + "," +
books[index]["target"] +
"</div>";
}
booksContainer.innerHTML = str
}
$.ajax({
type: "get",
async: false,
url: "http://www.softwhy.com/demo/JSON/php/antzone.php?callback=books",
dataType: "jsonp",
jsonp: "callback", //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback: "books", //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function (json) {
books(json)
},
error: function () {
console.log('fail');
}
});
});
</script>
</head>
<body>
<div id="books"></div>
</body>
</html>
5.总结
(1)JSONP并不是一个官方的标准协议,而是程序员自己达成的一种约定俗成。
(2)实现跨域就是利用<script>
标签自带的跨域能力。
(3)在请求页面创建一个用来处理数据的函数。
(4)处理数据的函数名称会被发送到服务器,经过包装以后,要被处理的数据被当作函数的参数返回。
(5)后台包装返回的字符串通过src加入scrpt标签后就是一个js函数调用代码,于是跨域请求成功。