导读
为了弥补AJAX无法跨域的问题,JSONP应运而生。不过JSONP并不是唯一跨域的技术,更新的有CORS技术。
简介
JSONP是JSON with padding(填充式JSON或参数式JSON)的简写,是应用JSON的一种新方法。JSONP看起来和JSON差不多,只不过是被包含在函数调用中的JSON,就像下面这样。callback({ "name": "real"})
。下面分别来谈谈JSON和JSONP。
JSON
JSON的优点
- JSON是一种数据格式。
- 基于纯文本,跨平台不是问题。
- JavaScript原生支持。JSON是JavaScript的一个严格的子集,利用了JavaScript中的一些模式(对象、数组等)来表示结构化数据。
- 经过合理的排版后可读性较强,XML过于繁琐、冗长。
- 容易编写和解析(JSON.stringify、JSON.parse),前提是要知道格式。
JSON数据的规则
JSON的语法可以表示为以下三种类型的值。
1、简单值:字符串,数值,布尔值,null。但不支持undefined。如:5,”hello”,false。值得注意的是:JSON字符串必须使用双引号(单引号会导致语法错误)。
2、对象:”{}/Object”。对象是一种复杂数据类型。是一组无序的键值对。而每个键值对中的值可以使简单值(字符串),也可以是复杂数据类型(数组,对象)。
{
"name": "real","age": 20,"friends": ["Laki","Sonny"] }
3、数组: “Array”。数组也是一种复杂数据类型,表示有序的值列表。其中数组中的值可以是简单数据类型(字符串),也可以复杂数据类型(数组、对象)。
[
{
"name": "Laki","age": "21" },{
"name": "Sonny","age": "22","friens": [ "real","Laki" ] }
]
对于日期类型:
var day = {
date: new Date( 2016,10,2 )
}
var jsonDay = JSON.stringify( day );// 转换为JSON格式
/* 解析 */
var day2 = JSON.parse( jsonDay,function ( key,value) {
if ( key === "date" ) {
return new Date( value );
} else {
return value;
}
})
是的,JSON.stringify()有三个参数,JSON.parse()有两个参数。只不过我们平常只用第一个。详细的可以参考其他资料。
JSONP
1、JSONP是为了解决跨域问题产生的,为了弥补AJAX的不足。AJAX请求跨域资源,Chrome下会报错:
XMLHttpRequest cannot load http://api.douban.com/book/subjects?q=javascript&alt=json&max-results=1. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost’ is therefore not allowed access.。说的是服务器端没有设置允许的请求源。
后端头部信息加上Access-Control-Allow-Origin: *
可以解决(CORS)。
2、但是对于img、ifame、script等,我们发现,在它们的src中引用其他域的资源的时候,是可以加载的(对于iframe,如果跨域,虽然可以加载,但是无法进行DOM操作,postMessage可以解决)。
3,JSONP正式基于上述的技术:
4,上述的函数就是我们常说的callback函数(函数名随意),callback函数接受数据(通常是json),进行解析并处理。
/* 前台 */
<script> window.onload = function () { var oBtn1 = document.getElementById( 'btn1' ); oBtn1.onclick = function () { var oScript = document.createElement( 'script' ); oScript.src = 'http://test.com/abc.PHP?t=str&callback=fn'; document.body.appendChild( oScript ); } } function fn( data ) { alert( data ); } function fn1 (data) { alert(data); } </script>
/* 后台:http://test.com/abc.PHP */
<?PHP
$t = isset($_GET['t']) ? $_GET['t'] : 'num';
$callback = isset($_GET['callback']) ? $_GET['callback'] : 'fn1';
$arr1 = array('111111','22222222','33333333','4444444','555555555555555555555');
$arr2 = array('aaaaaaaaaaaa','bbbbbbbb','cccccccccccc','ddddddddd','eeeeeeeeeeee');
if ($t == 'num') {
$data = json_encode($arr1);
} else {
$data = json_encode($arr2);
}
echo $callback.'('.$data.');';
可以看到,我们传递的callback指定了要处理数据的函数。
5,如果我们不显示指明回调函数callback的话,那么会需要频繁的改动后台数据。
比如对于上例,后台需要分别输出:
echo 'fn('.$data.')';
echo 'fn1('.$data.')';
显然,这样是远远没有使用callback回调参数方便的。
Jquery中JSONP的写法
好吧,可能大家都用的jq,这里就里jq来写一个。以上述第4点给出的前端代码为例,其Jquery写法是:
$.ajax({ type: "get",url: "getData.PHP",dataType : 'jsonp',success: function ( data ) { console.log( data ); }
});
对上面那么点代码,又有一些有趣的探讨。
Q:dataType : 'jsonp',
不写行不行?
A:不写会返回一个函数。参数是后端返回的数据。比如jQuery20009081766414813617_1475405628630(["111111","22222222","33333333","4444444","555555555555555555555"]);
这是上述例子返回的。
Q:可以手动指定回调函数吗?
A:正如上面一个问答,我们看到,回调函数是jQuery生成的一个函数。如果我们手动指定,只需要success: fn1
。然后自己定义一个fn1函数即可。
Q:前端没指定callback,那么后端的$callback是什么?
A:估计很多伙伴没有思考过这个问题。是”fn1”吗?答案是:不是。因为我们在请求的时候,jQ内部给我们手动添加了一个参数callback=***
。这是我从chrome中看到的参数:
callback:jQuery200039165487775940955_1475409598758
_:1475409598759
后面是时间参数,前面就不知道了。。所以我们在后端获取callback是可以获取到的。但是比方说改成callback2就不可以获取到了,那么,$callback = ‘fn1’。
好了,关于jQuery中的jsonp暂时就介绍这么多,有机会再介绍。
应用实例(百度搜索)
<!DOCTYPE HTML>
<html>
<head>
<Meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<style> *{ margin: 0; padding: 0; } #q{ width: 300px;; height: 30px; padding: 5px; border: 1px solid #f90; font-size:16px; } #q:focus { /*outline:0;*/ border: 1px solid #f90; outline: 1px solid #f90; } #ul1 { display:none; border: 1px solid #f90; width:310px; } li a { display: block; width: 310px; height: 24px; padding: 5px 0; color: #666; text-decoration: none; } li a:hover { background: #f90; color: white; } </style>
</head>
<body>
<input type="text" id="q" />
<ul id="ul1">
</ul>
<script> window.onload = function () { var oQ = document.getElementById( 'q' ); var oUl = document.getElementById( 'ul1' ); oQ.onkeyup = function () { if ( this.value !== '' ) { var oScript = document.createElement( 'script' ); /*以json形式返回数据,否则返回array类型*/ oScript.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+ this.value +'&json=1&cb=customFunction&_'+ new Date().getTime(); document.body.appendChild( oScript ); } else { oUl.style.display = 'none'; } } } function customFunction (data) { console.log( data ); var html = '',oUl = document.getElementById( 'ul1' ); if ( data.s.length ) { //搜索结果存在,百度搜索当搜索框值很多的时候,没有了结果。比如ddddddddddd... oUl.style.display = 'block'; for ( var i = 0,len = data.g.length; i < len; i++ ) { html += '<li><a href="https://www.baidu.com/s?ie=utf-8&wd='+ data.g[i].q +'">'+ data.g[i].q +'</a></li>'; } } oUl.innerHTML = html; } </script>
</body>
</html>
关于对百度请求url。可参考我的另一篇文章。http://www.jb51.cc/article/p-arswfmnn-od.html
是不是和百度的一模一样呢。
小结
1,大致讲了JSON数据格式。
2,JSONP的原理。
3,JSONP模拟的百度搜索。
4,给出了JS操作JSONP和JQ操作JSONP的例子。
参考
JavaScript高级程序设计,第三版。