为了理解json和jsonp,先提一下ajax;提到ajax就会不可避免的面临两个问题:
(1)ajax以何种格式来交换数据?
(2)跨域的需求如何解决?
ajax不允许跨域,可以用jsonp来解决
目前有很多方法来解决解决这个问题,但现在比较推崇的方法是,用json来交换数据,并靠jsonp来跨域。
json:是一种数据交换格式;
优点:1)基于纯文本,跨平台传递极其简单;
2)JavaScript原声支持,后台语言几乎全部支持;
3)轻量级数据格式,占用字符数量极少,特别适合互联网传递;
4)可读性较强,虽然比不上xml那么一目了然,但在合理的依次缩进之后还是很容易识别的;
5)容易编写和解析,当然前提是你要知道数据结构;
规则:1)json只有两种数据类型描述符,大括号{}和方括号[],其余英文冒火:是映射符,英文逗号','是分隔 符,引文双引号是定义符;
2)大括号用来描述一组‘不同类型的无序键值对集合’(每个键值对可以理解为oop的属性描述),方 括号[]用来描述一组“相同类型的有序数据集合”(可对应oop的数组);
3)上述两种集合中若有多个子项,则通过英文逗号,进行分隔;
4)键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号“”,以便于不同语言解析;
5)json内部常用的数据类型无非就是字符串,数字,布尔,日期,null这么几个,字符串必须用双 引号引起来,其余的不用,日期类型比较特殊。建议,如果客户端没有按日期排序功能需求的话, 那么把日期时间直接作为字符传递就好,可以省去很多麻烦。
Json代码实例:
//描述一个人
var person = {
"Name":"ShenLu",
"Age":25,
"Company":"ali",
"Engineer":true
}
//获取人的信息
var personAge = person.Age;
//描述几个人 var members = [ { "Name":"ShenLu", "Age":24, "Company":"Ali", "Engineer":true }, { "Name":"John", "Age":24, "Company":"Oracle", "Engineer":false } ]
//读取其中John的公司名称
var johnsCompany=members[1].Company;
//描述一场会议 var conference = { "Conference":"Future Marketing", "Date":"2017-06-18", "Address":"ShangHai", "Members":[ {
},{"Name":"ShenLu", "Age":24, "Company":"Ali", "Engineer":true
}]}"Name":"John", "Age":24, "Company":"Oracle", "Engineer":false
读取参会者Shenlu是否是工程师
var ShenluEngineer=conference.Members[0].Engineer;
jsonp:一种非官方跨域数据交互协议;
帮助理解:
1)ajax直接请求普通文件存在跨域无权限访问的问题,无论是你是静态页面,动态网页,只要是跨域要求,一律都不可以;
2)但是web页面上调用js文件时则不受跨域的影响(不仅如此,只要有src这个属性的标签都有跨域的能力,如<script><img><iframe>)
3)目前,如果想通过纯web端跨域访问数据只有一种可能,就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;
4)恰巧有json纯字符数据格式可以整洁的描述负责数据,更妙的是json还被js原声支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
5)这样,web客户端可以通过调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以接送为后缀),所以服务器之所以要动态生成json文件,目的记载于把客户端需要的数据装进去。
6)客户端对json文件调用成功之后,也就获得了自己需要的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常想ajax,但其实并不一样。
7)为了方便客户端使用数据,逐渐形成了一种非正式传输协议,人们称为jsonp,给协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据,这样客户端可以随意定制自己的函数来自动处理返回数据了。
jsonp是目前主流的实现跨域通信的解决方法;
在jQuery中可以通过$.ajax的对dataType设为jsonp来调用jsonp,但注意jsonp和ajax的实现原理一点关系都没有。。
jquery用ajax实现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>
jsonp主要是通过script链接远程url来实现跨域请求的。
<script src="http://jsonp.js?callback-XXX"></script>
借用一个他人写的函数var JSONP = { // 获取当前时间戳 now: function() { return (new Date()).getTime(); }, // 获取16位随机数 rand: function() { return Math.random().toString().substr(2); }, // 删除节点元素 removeElem: function(elem) { var parent = elem.parentNode; if(parent && parent.nodeType !== 11) { parent.removeChild(elem); } }, // url组装 parseData: function(data) { var ret = ""; if(typeof data === "string") { ret = data; } else if(typeof data === "object") { for(var key in data) { ret += "&" + key + "=" + encodeURIComponent(data[key]); } } // 加个时间戳,防止缓存 ret += "&_time=" + this.now(); ret = ret.substr(1); return ret; }, getJSON: function(url, data, func) { // 函数名称 var name; // 拼装url url = url + (url.indexOf("?") === -1 ? "?" : "&") + this.parseData(data); // 检测callback的函数名是否已经定义 var match = /callback=(\w+)/.exec(url); if(match && match[1]) {
name = match[1]; } else { // 如果未定义函数名的话随机成一个函数名 // 随机生成的函数名通过时间戳拼16位随机数的方式,重名的概率基本为0 // 如:jsonp_1355750852040_8260732076596469 name = "jsonp_" + this.now() + '_' + this.rand(); // 把callback中的?替换成函数名 url = url.replace("callback=?", "callback="+name); // 处理?被encode的情况 url = url.replace("callback=%3F", "callback="+name); } // 创建一个script元素 var script = document.createElement("script"); script.type = "text/javascript"; // 设置要远程的url script.src = url; // 设置id,为了后面可以删除这个元素 script.id = "id_" + name; // 把传进来的函数重新组装,并把它设置为全局函数,远程就是调用这个函数 window[name] = function(json) { // 执行这个函数后,要销毁这个函数 window[name] = undefined; // 获取这个script的元素 var elem = document.getElementById("id_" + name); // 删除head里面插入的script,这三步都是为了不影响污染整个DOM啊 JSONP.removeElem(elem); // 执行传入的的函数 func(json); }; // 在head里面插入script元素 var head = document.getElementsByTagName("head"); if(head && head[0]) { head[0].appendChild(script); } } };
调用发放和jQuery类似:
var
data = {
from:
"北京"
,
count: 27,
output:
"json"
,
callback:
"?"
}
json是目的,而jsonp是手段。JSONP.getJSON(
"http://api.qunar.com/cdnWebservices.jcp"
, data,
function
(json) {console.log(json)});