先前的概念中对JSON还是比较熟悉,对JSONP不是特别的清楚,整理完相关知识发现才豁然开朗。简单的说JSON是一种数据交换格式,而JSONP是一种非官方跨域数据交互协议。JSON是“暗号”,而JSONP则是接头方式。一个是描述信息的格式,一个是信息传递双方约定的方法。
一、什么是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建构于两种结构:
- “名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
- 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
JSON具有以下这些形式:
对象是一个无序的“‘名称/值’对”集合。一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。
数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
值(value)可以是双引号括起来的字符串(string)、数值(number)、true
、false
、 null
、对象(object)或者数组(array)。这些结构可以嵌套。
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
字符串(string)与C或者Java的字符串非常相似。
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
空白可以加入到任何符号之间。 以下描述了完整的语言。
JSON的优点:
- 基于纯文本,跨平台传递极其简单;
- Javascript原生支持,后台语言几乎全部支持;
- 轻量级数据格式,占用字符数量极少,特别适合互联网传递;
- 可读性较强,虽然比不上XML那么一目了然,但在合理的依次缩进之后还是很容易识别的;
- 容易编写和解析,当然前提是你要知道数据结构;
JSON实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
// 描述一个人
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
;
|
二、什么是JSONP?
JSONP(JSON with Padding)是资料格式 JSON 的一种“使用模式”,可以让网页从别的网域要资料。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com 的服务器沟通,而 HTML 的 元素是一个例外。利用
元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的 JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
为了理解这种模式的原理,先想像有一个回传 JSON 文件的 URL,而 JavaScript 程式可以用 XMLHttpRequest 跟这个 URL 要资料。假设我们的 URL 是http://server2.example.com/RetrieveUser?UserId=xxx 。假设小明的 UserId 是 1823,且当浏览器透过 URL 传小明的 UserId,也就是抓取http://server2.example.com/RetrieveUser?UserId=1823 ,得到:
1
|
{
"Name"
:
"小明"
,
"Id"
:
1823
,
"Rank"
:
7
}
|
这个 JSON 资料可能是依据传过去 URL 的查询参数动态产生的。
这个时候,把 元素的 src 属性设成一个回传 JSON 的 URL 是可以想像的,这也代表从 HTML 页面透过 script 元素抓取 JSON 是可能的。
然而,一份 JSON 文件并不是一个 JavaScript 程式。为了让浏览器可以在 元素执行,从 src 里 URL 回传的必须是可执行的 JavaScript。在 JSONP 的使用模式里,该 URL 回传的是由函数呼叫包起来的动态生成 JSON,这就是JSONP 的“填充(padding)”或是“前辍(prefix)”的由来。
惯例上浏览器提供回调函数的名称当作送至服务器的请求中命名查询参数的一部份,例如:
1
|
|
服务器会在传给浏览器前将 JSON 数据填充到回调函数(parseResponse)中。浏览器得到的回应已不是单纯的资料叙述而是一个脚本。在本例中,浏览器得到的是:
1
|
parseResponse
(
{
"Name"
:
"Cheeso"
,
"Id"
:
1823
,
"Rank"
:
7
}
)
|
虽然这个填充(前辍)“通常”是浏览器执行背景中定义的某个回调函数,它也可以是变量赋值、if 叙述或者是其他 JavaScript 叙述。JSONP 要求(也就是使用 JSONP 模式的请求)的回应不是 JSON 也不被当作 JSON 解析——回传内容可以是任意的运算式,甚至不需要有任何的 JSON,不过惯例上填充部份还是会触发函数调用的一小段 JavaScript 片段,而这个函数呼叫是作用在 JSON 格式的资料上的。
另一种说法—典型的 JSONP 就是把既有的 JSON API 用函数呼叫包起来以达到跨域存取的解法。为了要启动一个 JSONP 呼叫(或者说,使用这个模式),你需要一个 script 元素。因此,浏览器必须为每一个 JSONP 要求加(或是重用)一个新的、有所需 src 值的