什么是JSON?
JSON:JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
JSON的格式或者叫规则:
JSON能够以非常简单的方式来描述数据结构,XML能做的它都能做,因此在跨平台方面两者完全不分伯仲。
1、JSON只有两种数据类型描述符,大括号{}和方括号[],其余英文冒号:是映射符,英文逗号,是分隔符,英文双引号”“是定义符。
2、大括号{}用来描述一组“不同类型的无序键值对集合”(每个键值对可以理解为OOP的属性描述),方括号[]用来描述一组“相同类型的有序数据集合”(可对应OOP的数组)。
3、上述两种集合中若有多个子项,则通过英文逗号,进行分隔。
4、键值对以英文冒号:进行分隔,并且建议键名都加上英文双引号””,以便于不同语言的解析。
5、JSON内部常用数据类型无非就是字符串、数字、布尔、日期、null 这么几个,字符串必须用双引号引起来,其余的都不用,日期类型比较特殊,这里就不展开讲述了,只是建议如果客户端没有按日期排序功能需求的话,那么把日期时间直接作为字符串传递就好,可以省去很多麻烦。
数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
字符串(string)与C或者Java的字符串非常相似。
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
空白可以加入到任何符号之间。 以下描述了完整的语言。
JSON的优点:
- 基于纯文本,跨平台传递极其简单;
- Javascript原生支持,后台语言几乎全部支持;
- 轻量级数据格式,占用字符数量极少,特别适合互联网传递;
- 可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;
- 容易编写和解析,当然前提是你要知道数据结构;
// 描述一个人
var person = {
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
}
// 获取这个人的信息
var personAge = person.Age;
// 描述几个人
var members = [
{
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
},
{
"Name": "John",
"Age": 20,
"Company": "Oracle",
"Engineer": false
},
{
"Name": "Henry",
"Age": 45,
"Company": "Microsoft",
"Engineer": false
}
]
// 读取其中John的公司名称
var johnsCompany = members[1].Company;
// 描述一次会议
var conference = {
"Conference": "Future Marketing",
"Date": "2012-6-1",
"Address": "Beijing",
"Members":
[
{
"Name": "Bob",
"Age": 32,
"Company": "IBM",
"Engineer": true
},
{
"Name": "John",
"Age": 20,
"Company": "Oracle",
"Engineer": false
},
{
"Name": "Henry",
"Age": 45,
"Company": "Microsoft",
"Engineer": false
}
]
}
// 读取参会者Henry是否工程师
var henryIsAnEngineer = conference.Members[2].Engineer;
- JSON.parse: 把json格式的字符串转化成json格式的对象eval
- JSON.stringify:把json格式的对象转化成一个json格式的字符串
1、一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准;
2、不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>);
3、于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理;
4、恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
5、这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
6、客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
如果对于callback参数如何使用还有些模糊的话,我们后面会有具体的实例来讲解。
- 1.在当前js中声明一个全局函数
- function fn(data){这里就是获取数据的地方}
- 2.动态创建script标签
- 通过script标签引用其他网站并且将这个全局函数名字传递给后台
- 3.后天返回函数执行
- res.end('fn({name:1})');
- 总结:jsonp就是利用<script>标签中src属性能够跨域访问的特性,先定义了一个回调方法,然后将其当作url参数的一部分发送到服务端,服务端通过字符串拼接的方式将数据包裹在回调方法中,再返回回来
<script>
var url = "http://localhost:8080/crcp/rcp/t99eidt/testjson.do?jsonp=callbackfunction";
var script = document.createElement('script');
script.setAttribute('src', url); //load javascript
document.getElementsByTagName('head')[0].appendChild(script);
//回调函数
function callbackfunction(data){
var html=JSON.stringify(data.RESULTSET);
alert(html);
}
</script>
JSONP具体实现
前端代码在域www.practice.com下面,使用ajax发送了一个跨域的get请求
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type : "get",
async: false,
url : "http://www.practice-zhao.com/student.php?id=1",
type: "json",
success : function(data) {
jsonhandle(data);
}
});
});
</script>
</body>
</html>
后端PHP代码放在域www.practice-zhao.com下,简单的输出一段json格式的数据
jsonhandle({
"age" : 15,
"name": "John",
})
当访问页面是会报错:
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript" src="http://www.practice-zhao.com/remote.js"></script>
</body>
</html>
这里调用了跨域的remote.js脚本,remote.js代码如下:
jsonhandle({
"age" : 15,
"name": "John",
})
也就是这段远程的js代码执行了上面定义的函数,弹出了提示框 <!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript">
function jsonhandle(data){
alert("age:" + data.age + "name:" + data.name);
}
</script>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
var url = "http://www.practice-zhao.com/student.php?id=1&callback=jsonhandle";
var obj = $('<script><\/script>');
obj.attr("src",url);
$("body").append(obj);
});
</script>
</body>
</html>
这里动态的添加了一个script标签,src指向跨域的一个php脚本,并且将上面的js函数名作为callback参数传入,那么我们看下PHP代码怎么写的:<?php
$data = array(
'age' => 20,
'name' => '张三',
);
$callback = $_GET['callback'];
echo $callback."(".json_encode($data).")";
return;
PHP代码返回了一段JS语句,即jsonhandle({
"age" : 15,
"name": "张三",
})
此时访问页面时,动态添加了一个script标签,src指向PHP脚本,执行返回的JS代码,成功弹出提示框。 所以JSONP将访问跨域请求变成了执行远程JS代码,服务端不再返回JSON格式的数据,而是返回了一段将JSON数据作为传入参数的函数执行代码。
4.最后jQuery提供了方便使用JSONP的方式,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>GoJSONP</title>
</head>
<body>
<script type="text/javascript" src="jquery-1.8.3.min.js">
</script>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type : "get",
async: false,
url : "http://www.practice-zhao.com/student.php?id=1",
dataType: "jsonp",
jsonp:"callback", //请求php的参数名
jsonpCallback: "jsonhandle",//要执行的回调函数
success : function(data) {
alert("age:" + data.age + "name:" + data.name);
}
});
});
</script>
</body>
</html>
优点:
它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分 开了。我提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个jsonp服务。
缺点:
1.jsonp只支持get请求而不支持post请求,也即是说如果想传给后台一个json格式的数据,此时问题就来了,浏览器会报一个http状态码
415错误,告诉你请求格式不正确,这让我很蛋
疼(在登录注册中需要给后台传一大串数据),如果都用参数的形式拼接在url后面的话不太现实,后台取值也会显得繁琐,
2.在登录模块中需要用到session来判断当前用户的登录状态,这时候由于是跨域的原因,前后台的取到的session是不一样的,那么就不
能就行session来判断.
3.由于jsonp存在安全性问题(不知qq空间的跨域是怎么解决的,还是另有高招?)
后来考虑到上面的一系列问题,采用的是后台进行设置允许跨域请求(但还是存在缺陷的,实质上还是跨域,如上面说的session问题)
.Header set Access-Control-Allow-Origin *
为了防止XSS攻击我们的服务器, 我们可以限制域,比如
Access-Control-Allow-Origin: http://blog.csdn.net
3.安全防范:
1.防止callback参数意外截断js代码,特殊字符单引号双引号,换行符存在风险.
2.防止callback参数恶意添加script标签,造成xss漏洞
3.防止跨域请求滥用,阻止非法站点恶意调用
详细请看:http://blog.csdn.net/qq_39598092/article/details/78634693