参考文章来源:JSON教程(非常详细)
目录
JSON
JSON 发展史
为什么要使用 JSON?
JSON 的不足
存储格式
使用场景
1) 定义接口
2) 序列化
3) 生成 Token
4) 配置文件
JSON语法规则
JSON 与 JavaScript 对象的区别
JSON数据类型
1、字符串
2、数字
3、布尔值
4、空
5、对象
6、数组
JSON注释
JSON5
前端使用
示例
运行结果
JSON Schema
定义 Schema
Schema 中提供了一系列关键字
1) 字符串(String)
2) 数值类型
3) 对象
属性(Properties)
额外属性(Asdditional Properties)
必须属性(Required Properties)
属性名称(Property names)
属性个数(Size)
4) 数组
列表验证(List validation)
元组验证(Tuple validation)
数组长度(Length)
唯一(Uniqueness)
5) 布尔(boolean)
6) 空值(null)
7) 通用关键字
注释(Comments)
枚举值(Enumerated values)
常量值(Constant values)
8) $schema 关键字
9) $ref 关键字
10) $id 关键字
JSON和XML的区别
什么是 XML?
样例
优点
JSON 与 XML 之间的差异
JSON和BSON的区别
什么是 BSON?
JSON 与 BSON 之间的区别
不同语言的解析和创建
PHP
json_encode()
json_decode()
Python
json.dumps()
json.loads()
Java
使用 Java 解析 JSON 数据
Ajax
扩展知识JSONP是什么?
同源策略
什么是 JSONP?
如何实现 JSONP
总结
JSON
JSON 全称“JavaScript Object Notation”,译为“JavaScript 对象简谱”或“JavaScript 对象表示法”,是一种轻量级的、基于文本的、开放的数据交换(数据交换是指,两个设备之间建立连接并互相传递数据的过程)格式。是一种纯字符串形式的数据,它本身不提供任何方法(函数),非常适合在网络中进行传输。
JSON 发展史
2000 年初,Douglas Crockford(道格拉斯·克罗克福特)发明了 JSON,并从 2001 年开始推广使用。同年 4 月,位于旧金山湾区某车库的一台计算机发出了首个 JSON 格式的数据,这是计算机历史上的重要时刻。
图:道格拉斯·克罗克福特
2005-2006 年,JSON 正式成为主流的数据格式,雅虎、谷歌等知名网站开始广泛使用 JSON 格式。
2013 年,ECMA International(欧洲计算机制造商协会)制定了 JSON 的语法标准——ECMA-404。
经过 20 年左右的发展,JSON 已经替代了 XML,成为了 Web 开发中首选的数据交换格式。
为什么要使用 JSON?
JSON和XML都能够实现在互联网中数据传输。之所以使用 JSON,最主要的原因是 JavaScript。众所周知,JavaScript 是 Web 开发中不可或缺的技术之一,而 JSON 是基于 JavaScript 的一个子集,JavaScript 默认就支持 JSON,而且只要您学会了 JavaScript,就可以轻松地使用 JSON,不需要学习额外的知识。
- 结构简单、紧凑:与 XML 相比,JSON 遵循简单、紧凑的风格,有利于程序员编辑和阅读,而 XML 相对比较复杂;
- 更快:JSON 的解析速度比 XML 更快(因为 XML 与 HTML 很像,在解析大型 XML 文件时需要消耗额外的内存),存储同样的数据,JSON 格式所占的存储空间更小;
- 可读性高:JSON 的结构有利于程序员阅读。
JSON 的不足
- 只有一种数字类型:JSON 中只支持 IEEE-754 双精度浮点格式,因此您无法使用 JSON 来存储许多编程语言中多样化的数字类型;
- 没有日期类型:在 JSON 中您只能通过日期的字符串(例如:1970-01-01)或者时间戳(例如:1632366361)来表示日期;
- 没有注释:在 JSON 中无法添加注释;
- 冗长:虽然 JSON 比 XML 更加简洁,但它并不是最简洁的数据交换格式,对于数据量庞大或用途特殊的服务,您需要使用更加高效的数据格式。
存储格式
JSON 数据可以存储在 .json 格式的文件中(与 .txt 格式类似,都属于纯文本文件),也可以将 JSON 数据以字符串的形式存储在数据库、Cookie、Session 中。
使用场景
1) 定义接口
- 使用 Ajax 异步加载的数据;
- RPC 远程调用;
- 前后端分离,后端返回的数据;
- 开发 API,例如百度、高德的一些开放接口。
2) 序列化
程序在运行时所有的变量都是存储在内存中的,将这些数据保存到数据库中,也可以保存到一个文件中,这个将内存中数据保存起来的过程称为序列化。序列化在 Python 中称为 pickling,在其他语言中也被称为 serialization、marshalling、flattening 等等,都是一个意思。
通常情况下,序列化是将程序中的对象直接转换为可保存或者可传输的数据,但这样会保存对象的类型信息,无法做到跨语言使用,例如我们使用 Python 将数据序列化到硬盘,然后使用 Java 来读取这份数据,这时由于不同编程语言的数据类型不同,就会造成读取失败。如果在序列化之前,先将对象信息转换为 JSON 格式,则不会出现此类问题。
3) 生成 Token
JSON 格式的 Token 最有代表性的是 JWT(JSON Web Tokens)
JSON Web Token Introduction - jwt.io
4) 配置文件
npm(Node.js 的包管理工具)的 package.json {"name": "server","version": "0.0.0","private": true,"main": "server.js","scripts": {"start": "node ./bin/www"},"dependencies": {"cookie-parser": "~1.4.3","debug": "~2.6.9","express": "~4.16.0","http-errors": "~1.6.2","jade": "~1.11.0","morgan": "~1.9.0"}
}
JSON语法规则
- Object(对象):键/值对(名称/值)的集合,使用花括号
{ }
定义。在每个键/值对中,以键开头,后跟一个冒号:
,最后是值。多个键/值对之间使用逗号,
分隔,例如{"name":"C语言中文网","url":"http://c.biancheng.net"}
; - Array(数组):值的有序集合,使用方括号
[ ]
定义,数组中每个值之间使用逗号,
进行分隔。 - 键:JSON 数据是以键/值对(名称/值)的形式书写的,键表示数据的名称,需要以字符串的形式定义(在双引号中定义),后面紧跟一个冒号,最后是值,如下例所示:
"name":"C语言中文网"
- 值:支持很多数据类型。
- 数字(整数或浮点数);
- 字符串(需要在双引号中定义);
- 布尔值(true 或 false);
- 数组(在方括号中定义);
- 对象(在花括号中定义);
- null(空)。
JSON 与 JavaScript 对象的区别
JSON 是一种数据交换格式,可以跨语言、跨平台使用,它只是与 JavaScript 有些渊源,并不是 JavaScript 的一部分。
在 JavaScript 对象中,您既可以使用双引号也可以使用单引号,但在 JSON 中只能使用双引号。还有就是 JSON 中没有日期类型,也不能定义注释,所以您只能通过日期的字符串(例如:1970-01-01)或者时间戳(例如:1632366361)来表示日期。
语法:
// JavaScript 中的对象
{
foo: "bar"
}
// JSON
{
"foo": "bar"
}
JSON数据类型
1、字符串
字符串中也可以包含一些转义字符
\\
反斜线本身;\/
正斜线;\"
双引号\b
退格;\f
换页;\n
换行;\r
回车;\t
水平制表符;\u
四位的十六进制数字。
2、数字
JSON 中不区分整型和浮点型,只支持使用 IEEE-754 双精度浮点格式来定义数字。此外,JSON 中不能使用八进制和十六进制表示数字,但可以使用 e 或 E 来表示 10 的指数。
{"number_1" : 210,"number_2" : -210,"number_3" : 21.05,"number_4" : 1.0E+2
}
3、布尔值
{"message" : true,"pay_succeed" : false
}
4、空
{"id" : 1,"visibility" : true,"popularity" : null
}
5、对象
{"author": {"name": "一百减一是零","url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343"}
}
6、数组
{"course" : ["JSON 教程","JavaScript 教程","HTML 教程",{"website" : "一百减一是零","url" : "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343"},[3.14,true],null]
}
JSON注释
想要在 JSON 中添加注释,我们可以在要添加注释键/值对的前面(或后面)添加一个同名的键,并在键名中添加一个特殊字符加以区分,例如@
、#
、?
、_
、/
等,然后在与键对应的值中定义注释的内容。
{"@name": "网站名称","name": "一百减一是零","_url": "网址","url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","course": "JSON 教程","@charge": "0=收费; 1=免费","charge": 1,"#list": "教程目录","list": ["JSON数据类型","JSON对象","JSON数组"],"message": {"code": 0,"message": "OK","#data": {"#id": "用户ID","#type": "0=正常; 1=异常","#name": "姓名","#createTime": "创建时间(yyyy-MM-dd)"},"data": {"id": "12345","type": 0,"name": "我的名字","createTime": "2020-05-20"}}
}
除了可以在键名中添加特殊字符外,也可以直接以“comment”、“_comment” 或 “__comment”作为键名来定义注释,如下例所示:
{"_comment": "(https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343/)—— 一个在线学习编程的网站","course": {"name": "JSON 教程","url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343"}
}
JSON5
与 JSON 相比,JSON5 做出了如下改变:
- 在对象或数组的末尾(即最后一个键/值对或值),可以添加逗号;
- 字符串可以使用单引号定义;
- 字符串中可以包含转义字符,并且可以跨越多行;
- 可以定义十六进制的数字;
- 数字可以包含前导或后导的小数点;
- 数字前可以添加一个加、减号来表示正负数;
- 可以使用
//
来定义单行注释,使用/* ... */
来定义多行注释。
{// 网站名称"name": "一百减一是零",// 网址"url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","course": "JSON 教程",// 0=收费; 1=免费"charge": 1,// 教程目录"list": ["JSON数据类型","JSON对象","JSON数组"],"message": {"code": 0,"message": "OK",/*id = 用户IDtype = 0=正常; 1=异常name = 姓名createTime = 创建时间(yyyy-MM-dd)*/"data": {"id": "12345","type": 0,"name": "我的名字","createTime": "2020-05-20"}}
}
前端使用
引入<script src="https://unpkg.com/json5@^2.0.0/dist/index.min.js"></script>
示例
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"><title>JavaScript</title>
</head>
<body><script src="https://unpkg.com/json5@^2.0.0/dist/index.min.js"></script><script>var arr = {// 网站名称"name": "一百减一是零",// 网址"url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","course": "JSON 教程",// 0=收费; 1=免费"charge": 1,// 教程目录"list": ["JSON数据类型","JSON对象","JSON数组"],"message": {"code": 0,"message": "OK",/*id = 用户IDtype = 0=正常; 1=异常name = 姓名createTime = 创建时间(yyyy-MM-dd)*/"data": {"id": "12345","type": 0,"name": "我的名字","createTime": "2020-05-20"}}};var str = JSON5.stringify(arr);console.log(arr)</script>
</body>
</html>
运行结果
JSON Schema
在 JSON Schema 中可以规定要在 JSON 中出现的字段、字段含义、字段类型等信息,而且可以使用 JSON Schema 来校验 JSON 数据是否符合 Schema 中定义的规范。
定义 Schema
{"$schema": "http://json-schema.org/draft-04/schema#","type": "object","properties": {"name": { "type": "string" },"email": { "type": "string" },"age": {"type": "number","minimum": 0,"exclusiveMinimum": false},"telephone": {"type": "string","pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"}},"required": ["name", "email"],"additionalProperties": false
}
上面 Schema 中,要求 JSON 数据必须符合以下要求
- 类型为 object;
- JSON 中可以包含以下四个键:
- name:必须是字符串类型;
- email:必须是字符串类型;
- age:必须是大于 0 的整数;
- telephone:必须是字符串类型,并且需要匹配指定的正则表达式。
- 上面的四个键中,name 和 email 必须定义,而 age 和 telephone 则是可选的;
- 除了上面四个键,不允许出现其它的键。
Schema 中提供了一系列关键字
1) 字符串(String)
关键字 | 描述 | 可选值 |
---|---|---|
minLength | 字符串最小长度,不能为负数 | |
maxLength | 字符串最大长度,不能为负数 | |
pattern | 正则表达式 | |
format | 字符串格式 | "date-time":日期和时间,如 2018-11-13T20:20:39+00:00 "time":时间,如 20:20:39+00:00 "date":日期,如 2018-11-13 "email":电子邮箱地址 "hostname":主机名 "ipv4":IPv4 地址 "ipv6":IPv6 地址 "uri":通用资源标识符(URI) "uri-template":URI 模板(任何级别) "regex":正则表达式 |
2) 数值类型
关键字 | 描述 | 示例 |
---|---|---|
integer | 整数 | {"type": "integer"} |
number | 数字,包括整数和浮点数 | {"type": "number"} |
multipleOf | 数字必须是给定数字(正数)的倍数 | {"type": "number", "multipleOf": 3} |
minimum | 数值允许的最小值 | {"type": "number", "minimum": 1} |
maximum | 数值允许的最大值 | {"type": "number", "maximum": 9} |
3) 对象
属性(Properties)
{"type": "object","properties": {"name": { "type": "string"},"age": {"type": "number", "multipleOf": 3},"date": {"type": "string","format": "date"}}
}
额外属性(Asdditional Properties)
{"type": "object","properties": {"number": { "type": "number"},"street_name": { "type": "string"},"street_type": {"type": "string","enum": ["Street", "Avenue", "Boulevard"]}},"additionalProperties": { "type": "string"}
}
必须属性(Required Properties)
{"type": "object","properties": {"name": { "type": "string" },"email": { "type": "string" },"address": { "type": "string" },"telephone": { "type": "string" }},"required": ["name", "email"]
}
属性名称(Property names)
propertyNames 定义 JSON 数据中键的命名规则
{"type": "object","propertyNames": {"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"}
}
属性个数(Size)
{"type": "object","minProperties": 2,"maxProperties": 3
}
4) 数组
列表验证(List validation)
任意长度的数组,数组中每个值都匹配相同的 Schema;
验证数组的所有值为数字
{"type": "array","items": {"type": "number"}
}contains 关键字仅需要针对数组中的一个或多个项目进行验证,如下例所示(只需包含至少一个数字元素):{"type": "array","contains": {"type": "number"}
}
元组验证(Tuple validation)
固定长度的数组,数组中每个值可以匹配不同的 Schema。
值的类型也可能是不同的,例如:
[编号, 街道名称, 街道类型, 方向]{"type": "array","items": [{"type": "number"},{"type": "string"},{"type": "string","enum": ["Street", "Avenue", "Boulevard"]},{"type": "string","enum": ["NW", "NE", "SW", "SE"]}]
}
数组长度(Length)
{"type": "array","minItems": 2,"maxItems": 3
}
唯一(Uniqueness)
将 uniqueItems 关键字设置为 true 可以确保数组中的每个元素都是唯一的
{"type": "array","uniqueItems": true
}
5) 布尔(boolean)
{"type": "boolean"}
6) 空值(null)
{"type": "null"}
7) 通用关键字
- title 和 description 关键字必须是字符串,“title”最好比较简短,而“description”应该提供关于该 schema 的详细描述;
- default 关键字用来定义默认值;
- examples 关键字是用于提供一系列针对该模式进行验证的示例。
{"title": "Match anything","description": "This is a schema that matches anything.","default": "Default value","examples": ["Anything", 4035]
}
注释(Comments)
$comment 关键字用于添加注释/批注,它的值必须是一个字符串。
枚举值(Enumerated values)
enum 关键字被用于定义枚举值(一组固定的值),它必须是一个至少包含一个值的数组,而且每个值都必须是唯一的。此外,type 和 enum 是并列的,必须同时满足,如下例所示:
{"type": "string","enum": ["red", "amber", "green"]
}
常量值(Constant values)
const 关键字被用于定义一个常量值
{"properties": {"country": {"const": "United States of America"}}
}const 是 enum 的语法糖,所以下面两个定义是等价的:{ "const": "United States of America" }
{ "enum": [ "United States of America" ]}
8) $schema 关键字
$schema 关键字用于声明 JSON Schema 的版本,建议所有 JSON Schema 都声明一个 $schema,并且应该是 Schema 的第一个键/值对,如下例所示:
{"$schema": "http://json-schema.org/draft-04/schema#"}
如果需要声明 JSON Schema 的指定版本,则可以将 $schema 的值设置为以下几个:
- http://json-schema.org/draft-07/schema#
- http://json-schema.org/draft-06/schema#
- http://json-schema.org/draft-04/schema#
9) $ref 关键字
$ref 关键字用于引用其他地方的一个 Schema 片段,它的值为一个 URI 引用。如果是引用同一文档的 Schema 片段,则 $ref 的值需要以井号(#)开头,例如:
{ "$ref": "#/definitions/address" }
上面示例中的“#/definitions/address”意味着:
- 转到文档的根;
- 找到 "definitions" 键的值;
- 在该对象中,找到键 "address" 的值。
如果要引用另外的 Schema 文件,可以向下面这样:
{ "$ref": "definitions.json#/address" }
示例
{"$schema": "http://json-schema.org/draft-04/schema#","definitions": {"address": {"type": "object","properties": {"street_address": { "type": "string" },"city": { "type": "string" },"state": { "type": "string" }},"required": ["street_address", "city", "state"]}},"type": "object","properties": {"billing_address": { "$ref": "#/definitions/address" },"shipping_address": { "$ref": "#/definitions/address" }}
}
使用 $ref 关键字也可以引用当前 Schema 中的某一部分(类似于编程中的递归)。例如您有一个 person 模式,其中包含一个数组 children,每个数组也是一个 person 实例,如下例所示:
{"$schema": "http://json-schema.org/draft-07/schema#","definitions": {"person": {"type": "object","properties": {"name": { "type": "string" },"children": {"type": "array","items": { "$ref": "#/definitions/person" },"default": []}}}},"type": "object","properties": {"person": { "$ref": "#/definitions/person" }}
}
10) $id 关键字
$id 关键字的值是一个 URI 引用,它有两个用途:
- 为 Schema 声明一个唯一的标识符;
- 声明一个基本 URI,$ref 可以基于该 URI 进行引用。
例如我们要引用 http://c.biancheng.net/ 域名的某个 Schema,则可以将 $id 设置为下面这样:
{ "$id": "http://c.biancheng.net/schemas/address.json" }
注意,当定义了上面所示的 $id 之后,若我们要使用 $ref 来引用同域名下的其它 Schema,则可以简写成如下所示的样子
{ "$ref": "person.json" }
JSON和XML的区别
什么是 XML?
XML 全称“Extensive Markup Language”,译为“可扩展标记语言”,是一种源自 SGML 的、基于文本的数据格式(XML 是 SGML 的一个子集)。是一种专门为了存储数据而创建的标记语言,它的编写方式与 HTML 非常相似,能够通过不同的标签来标记不同的内容。XML 旨在传输或保存数据,而不是显示数据,在 XML 中,没有预定义标签,其中使用的所有标签都是自定义的,而且所有的标签都由两个部分组成,分别是开始标签(例如<tagname>)和结束标签(例如</tagname>)。需要注意的是,XML 中的标签是区分大小写的
样例
<?xml version="1.0" encoding="ISO-8859-1"?>
<note><title>JSON教程</title><author>一百减一是零</author><url>https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343</url><catalogue><li>JSON是什么?</li><li>JSONP是什么?</li><li>JSON语法规则</li> </catalogue>
</note>
优点
是它可以跨平台、跨语言进行传输。另外,XML 数据可以保存在格式为 .xml 的文本文件中。
JSON 与 XML 之间的差异
JSON | XML |
---|---|
JSON 是一种数据格式 | XML 是一种标记语言 |
与 XML 相比,JSON 数据更容易阅读 | XML 文档相对来说阅读起来比较困难 |
JSON 数据可以存储在 .json 格式的文本文件中 | XML 数据可以存储在 .xml 格式的文本文件中 |
JSON 中支持字符串、数字、数组、布尔值等类型 | XML 中只有字符串类型 |
JSON 没有显示功能 | XML 提供了显示数据的能力,因为它是一种标记语言 |
JSON 仅支持 UTF-8 编码 | XML 支持各种编码 |
JSON 不支持注释 | XML 支持注释 |
JSON 不支持命名空间 | XML 支持命名空间 |
JSON 读写速度更快,且更容易解析 | 相对于 JSON,XML 数据结构更加复杂,解析速度相对较慢 |
相对于 XML,JSON 的安全性较低 | 相对于 JSON,XML 的安全性更高 |
JSON和BSON的区别
什么是 BSON?
BSON 全称“Binary Serialized Document Format”,译为“二进制序列化文档格式”,是由 10gen(一家公司的名称)开发的一种数据格式,目前主要用于 MongoDB 数据库中,是 MongoDB 的数据存储格式。
BSON 基于 JSON,在 JSON 的基础上进行了升级,支持更多的数据类型。有时也将 BSON 称为“Binary JSON”,即“二进制 JSON”。
注意:BSON 并非只能用于 MongoDB,它也可以在其它编程语言中使用。
与 JSON 相比,BSON 存取的效率更高,而且占用的空间更小。另外,除了支持 JSON 中的数据类型外,BSON 还支持日期(Date)和二进制(BinData)等类型。
JSON 与 BSON 之间的区别
JSON 和 BSON 之间最主要的区别如下表所示:
JSON | BSON |
---|---|
JSON 是 javascript 对象表示法 | BSON 是二进制 JSON |
是一种轻量级的、基于文本的、开放的数据交换格式 | 是一种二进制序列化文档格式 |
JSON 包含一些基本数据类型,如字符串、数字、布尔值、空值 | 除了支持 JSON 中的类型外,BSON 还包含一些额外的数据类型,例如日期(Date)、二进制(BinData)等 |
AnyDB、redis 等数据库将数据存储为 JSON 格式 | MongoDB 中将数据存储为 BSON 格式 |
主要用于传输数据 | 主要用于存储数据 |
没有响应的编码和解码技术 | 有专用的编码和解码技术 |
如果想从 JSON 文件中读取指定信息,需要遍历整个数据 | 在 BSON 中,可以使用索引跳过到指定内容 |
JSON 格式不需要解析,因为它是人类可读的 | BSON 需要解析,因为它是二进制的 |
JSON 是对象和数组的组合,其中对象是键值对的集合,而数组是元素的有序列表 | BSON 是二进制数据,在其中可以存储一些附加信息,例如字符串长度、对象类型等 |
不同语言的解析和创建
PHP
- json_encode():可以将变量转换为 JSON 格式;
- json_decode():可以对 JSON 格式的字符串进行解析。
json_encode()
json_encode(mixed $value, int $options = 0, int $depth = 512): string | false
参数说明如下:
- $value:要转换的变量,变量可以是任意数据类型;
- $options:可选参数,默认值为 0,可选值为以下 PHP 常量:JSON_FORCE_OBJECT、JSON_HEX_QUOT、JSON_HEX_TAG、JSON_HEX_AMP、JSON_HEX_APOS、JSON_INVALID_UTF8_IGNORE、JSON_INVALID_UTF8_SUBSTITUTE、 JSON_NUMERIC_CHECK、JSON_PARTIAL_OUTPUT_ON_ERROR、JSON_PRESERVE_ZERO_FRACTION、JSON_PRETTY_PRINT、JSON_UNESCAPED_LINE_TERMINATORS、JSON_UNESCAPED_SLASHES、JSON_UNESCAPED_UNICODE、JSON_THROW_ON_ERROR。关于这些常量了解即可,一般不怎么使用,它们的具体含义您可以通过 JSON 常量查阅;
- $depth:可选参数,用来设置递归的最大深度,它的值必须大于 0,默认值为 512,同 $options 参数一样,该参数同样不怎么使用。
若转换成功,json_encode() 函数会返回字符串类型的转换结果,若转换失败,则返回 false。
示例
<?php$arr = ["title" => "JSON教程","author" => "一百减一是零","url" => "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue" => ["JSON是什么?","JSONP是什么?","JSON语法规则"]];echo json_encode($arr);
?>
运行结果
{"title":"JSON\u6559\u7a0b","author":"C\u8bed\u8a00\u4e2d\u6587\u7f51","url":"http:\/\/c.biancheng.net\/","catalogue":["JSON\u662f\u4ec0\u4e48\uff1f","JSONP\u662f\u4ec0\u4e48\uff1f","JSON\u8bed\u6cd5\u89c4\u5219"]}
通过运行结果可以看出,在使用 json_encode() 函数将变量转换为 JSON 数据时,会将变量中的中文字符编码为 Unicode 字符(\uXXXX 格式的字符),如果不需要这样的转换,将 json_encode() 函数的第二个参数设置为 JSON_UNESCAPED_UNICODE 即可,如下例所示:
<?php$arr = ["title" => "JSON教程","author" => "一百减一是零","url" => "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue" => ["JSON是什么?","JSONP是什么?","JSON语法规则"]];echo json_encode($arr,JSON_UNESCAPED_UNICODE );
?>
运行结果
{"title":"JSON教程","author":"C语言中文网","url":"http:\/\/c.biancheng.net\/","catalogue":["JSON是什么?","JSONP是什么?","JSON语法规则"]}
json_decode()
json_decode(string $json, bool $assoc = false, int $depth = 512, int $options = 0): mixed
参数说明如下:
- $json:必填参数,要解析的 JSON 字符串;
- $assoc:可选参数,默认值为 false,若将值设置为 true,那么 json_decode() 函数将返回一个数组;
- $depth:可选参数,用来设置递归的最大深度,默认值为 512,也可以设置为其它大于 0 的值;
- $options:可选参数,默认值为 0,可选值为 JSON_BIGINT_AS_STRING、JSON_INVALID_UTF8_IGNORE、JSON_INVALID_UTF8_SUBSTITUTE、JSON_OBJECT_AS_ARRAY、JSON_THROW_ON_ERROR 等常量,可以同时设置多个常量,常量之间使用竖线
|
进行分隔。有关上述常量的含义,您可以通过 PHP 预定义常量查阅。
若解析成功,json_decode() 函数会返回 JSON 中的数据,若解析失败,或者 JSON 的数据深度超过了递归的限制,则返回 null。
示例
<?php$str = '{"title":"JSON教程","author":"一百减一是零","url":"https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue":["JSON是什么?","JSONP是什么?","JSON语法规则"]}';echo "<pre>";var_dump(json_decode($str, true));
?>
运行结果
array(4) {["title"]=>string(10) "JSON教程"["author"]=>string(16) "一百减一是零"["url"]=>string(23) "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343"["catalogue"]=>array(3) {[0]=>string(16) "JSON是什么?"[1]=>string(17) "JSONP是什么?"[2]=>string(16) "JSON语法规则"}
}
Python
- json.dumps():将 Python 对象转换为 JSON 数据;
- json.loads():将 JSON 数据解析为 Python 对象。
json.dumps()
json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False, **kw)
参数说明如下:
- obj:要转换为 JSON 数据的 Python 对象;
- skipkeys:默认值为 False,如果 dict 中 keys 内的数据不是 Python 的基本类型(str、unicode、int、long、float、bool、None),会报 TypeError 错误,若设置为 True,则会跳过这类 key;
- ensure_ascii:默认值 True,即输出 ASCLL 码,若设置为 False,则可以输出中文;
- check_circular:如果值为 False,则跳过对容器类型的循环引用检查,循环引用将导致溢出错误;
- allow_nan:默认值 True,在处理 JSON 规范以外的 Float 类型时(例如:nan、inf、-inf),将其转换为 JavaScript 中的等价类型(例如:NaN、Infinity、-Infinity),若设置为 False,则会引发一个 ValueError 错误,
- cls:用来指定一个自定义的 JSONEncoder 子类,来替换 JSONCoder 类;
- indent:按照给定数值,将数据缩进显示,让数据读起来更加清晰;
- separators:分隔符,分别设置不同 dict 项之间的分隔符和 dict 项内 key 与 value 之间的分隔符,并将冒号
:
与逗号,
之后的空格全部去除;- encoding:设置 JSON 数据的编码方式,默认为 UTF-8;
- default:指定一个函数,当某个对象无法被序列化时会调用该函数;
- sort_keys:若值为 Ture,则表示按照 dict 排序(a 到 z)输出。
示例
import json
dictionary = {"title":"JSON教程","author":"一百减一是零","url":"https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue":["JSON是什么?","JSONP是什么?","JSON语法规则"]}
jsonString = json.dumps(dictionary, indent=4, ensure_ascii=False)
print(jsonString)
运行结果
{"title": "JSON教程","author": "一百减一是零","url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue": ["JSON是什么?","JSONP是什么?","JSON语法规则"]
}
json.loads()
json.loads(s[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]])
参数说明如下:
- s:要转换的 JSON 数据,可以是 str、bytes 或 bytearray 等类型;
- encoding:可选参数,设置 JSON 数据的编码方式,默认为 UTF-8;
- cls:可选参数,用于指定一个自定义 JSONCoder 的子类,来替换 JSONCoder 类;
- object_hook:可选参数,将函数的返回值替换为指定的类型,该功能可以用来实现自定义解码器,例如 JSON-RPC;
- parse_float:可选参数,如果指定该参数,那么在解码 JSON 数据时,符合 float 类型的字符串将转换为指定的类型;
- parse_int:可选参数,如果指定该参数,那么在解码 JSON 数据时,符合 int 类型的字符串将转换为指定的类型;
- parse_constant:可选参数,如果指定该参数,那么在解码 JSON 数据时,若出现 -Infinity、Infinity、NaN 等字符串,则调用指定的方法;
- object_pairs_hook:可选参数,将结果以 key-value 有序列表的形式返回,如果 object_hook 和 object_pairs_hook 同时指定的话,优先按照 object_pairs_hook 的设置返回。
示例
import json
json_str = '{"title":"JSON教程","author":"一百减一是零","url":"https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue":["JSON是什么?","JSONP是什么?","JSON语法规则"]}'
data = json.loads(json_str)
print(data)
运行结果
{'title': 'JSON教程', 'author': '一百减一是零', 'url': 'https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343', 'catalogue': ['JSON是什么?', 'JSONP是 什么?', 'JSON语法规则']}
Java
import org.json.simple.JSONObject;
class JsonEncodeDemo {public static void main(String[] args) {JSONObject obj = new JSONObject();obj.put("title", "JSON教程");obj.put("author", "一百减一是零");obj.put("url", "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343");obj.put("hits", 100);System.out.print(obj);}
}
运行结果
{"hits":100,"author":"一百减一是零","title":"JSON教程","url":"一百减一是零-CSDN博客"}
使用 Java 解析 JSON 数据
实例
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.parser.ParseException;
import org.json.simple.parser.JSONParser;
class JsonDecodeDemo {public static void main(String[] args) {JSONParser parser = new JSONParser();String s = "[0{\"hits\":100,\"author\":\"一百减一是零\",\"title\":\"JSON教程\",\"url\":\"https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343\"}]";try{Object obj = parser.parse(s);JSONArray array = (JSONArray)obj;System.out.println(array.get(1));System.out.println();}catch(ParseException pe) {System.out.println("position: " + pe.getPosition());System.out.println(pe);}}
}
运行结果
{"hits":100,"author":"一百减一是零","title":"JSON教程","url":"一百减一是零-CSDN博客"}
Ajax
Ajax 全称“Asynchronous JavaScript and XML”,译为“异步 JavaScript 和 XML”,程序员们习惯称之为“阿贾克斯”,通过 Ajax 我们可以异步在服务器与客户端之间传递数据。在 Ajax 中,普遍使用 JSON 作为传输数据的格式。
<!DOCTYPE html>
<html lang="en">
<head><meta content="text/html; charset=utf-8"><title>AJAX And JSON</title><script type="application/javascript">function load() {var url = "./data.json"; // 获取 JSON 数据的链接var request;if (window.XMLHttpRequest) {request = new XMLHttpRequest(); //发送 Ajax 请求,适用于 Chrome, mozilla 等浏览器 } else if (window.ActiveXObject) {request = new ActiveXObject("Microsoft.XMLHTTP"); // 发送 Ajax 请求,适用于 IE 浏览器 }request.onreadystatechange = function() {if (request.readyState == 4) {var jsonObj = JSON.parse(request.responseText); // 解析 JSON 数据document.getElementById("title").innerHTML = jsonObj.title;document.getElementById("author").innerHTML = jsonObj.author;document.getElementById("url").innerHTML = jsonObj.url;document.getElementById("catalogue").innerHTML = jsonObj.catalogue;}}request.open("GET", url, true);request.send();}</script>
</head>
<body>Title: <span id="title"></span><br />Author: <span id="author"></span><br />Url: <span id="url"></span><br />Catalogue: <span id="catalogue"></span><br /><button type="button" onclick="load()">点击加载 JSON 数据</button>
</body>
</html>
date.json 文件中的内容
{"title": "JSON教程","author": "一百减一是零","url": "https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343","catalogue": ["JSON是什么?","JSONP是什么?","JSON语法规则"]
}
运行结果
扩展知识JSONP是什么?
JSONP 不是一门编程语言,也不是什么特别的技术,它更像一个漏洞,程序员可以利用这个漏洞,实现跨域(可以简单理解为跨域名)传输数据
同源策略
同源策略是由 Netscape(网景)提出的一个著名的安全策略,所有支持 JavaScript 的浏览器都支持这个策略。
所谓同源是指域名、协议、端口都相同。以 http://c.biancheng.net:80/ 为例,c.biancheng.net 为域名,http 为协议,80 为端口(提示:80 为默认端口,可以省略,若为其它端口则必须显示定义)。
为了安全,浏览器不允许进行跨域请求。当我们通过 Ajax 在网页和服务器之间发送或接收数据时,需要保证网页与所请求的地址是同源的,否则无法请求成功。例如 http://c.biancheng.net/ 下的网页,只能与同在 http://c.biancheng.net/ 下的程序进行交互,无法与 https://www.baidu.com/ 下的程序进行交互。
同源策略可以防止 JavaScript 脚本从您的网站中读取数据,并将数据发送到其它的网站。如果没有同源策略,很有可能会有恶意的程序泄露您网站中的内容。
虽然同源策略在一定程度上提高了网站的安全,但也会给程序员带来一些麻烦,例如在访问一些开发接口时,由于同源策略的存在,会调用失败。要解决这种问题就需要用到跨域,跨域的方法有许多种,其中最经典的就是 JSONP。
什么是 JSONP?
JSONP 全称“JSON with Padding”,译为“带回调的 JSON”,它是 JSON 的一种使用模式。通过 JSONP 可以绕过浏览器的同源策略,进行跨域请求。
在进行 Ajax 请求时,由于同源策略的影响,不能进行跨域请求,而<script>
标签的 src 属性却可以加载跨域的 JavaScript 脚本,JSONP 就是利用这一特性实现的。与普通的 Ajax 请求不同,在使用 JSONP 进行跨域请求时,服务器不再返回 JSON 格式的数据,而是返回一段调用某个函数的 JavaScript 代码,在 src 属性种调用,来实现跨域。
JSONP 的优点是兼容性好,在一些老旧的浏览器种也可以运行,但它的缺点也非常明显,那就是只能进行 GET 请求。
如何实现 JSONP
假设我们要从网站 localhost:8080 向服务器 localhost:8081 下的发送请求,并在服务器返回如下内容:
{"name":"一百减一是零", "url":"一百减一是零-CSDN博客"}
如果直接发送 Ajax 请求,由于同源策略的存在,请求会被阻止,因为网站和服务器不同源。示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>JavaScript</title>
</head>
<body><div id="result"></div><button type="button" onclick="sendAjax()">发送请求</button><script>function sendAjax() {// 创建 XMLHttpRequest 对象var request = new XMLHttpRequest();// 实例化请求对象request.open("GET", "http://localhost:8081/test.php");// 监听 readyState 的变化request.onreadystatechange = function() {// 检查请求是否成功if(this.readyState === 4 && this.status === 200) {// 将来自服务器的响应插入当前页面document.getElementById("result").innerHTML = this.responseText;}};// 将请求发送到服务器request.send();}</script>
</body>
</html>
点击页面的“发送请求”按钮,会返回如下错误:
Access to XMLHttpRequest at 'http://localhost:8081/test.php' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET http://localhost:8081/test.php net::ERR_FAILED
想要成功从服务器中获取数据,就可以使用我们上面介绍的 JSONP 来实现,实现步骤如下:
使用<script>
标签,将标签的 src 属性设置为要请求的地址,如下所示:
<script src="http://localhost:8081/test.php"></script>
这时您会发现,<script>
标签会自动解析并执行返回的内容,如果这些内容不是完整的 JavaScript 代码,程序就会报错,所有在进行 JSONP 跨域请求时,需要保证服务器返回一段完整的 JavaScript 代码。
另外,返回的内容也不能是一段纯 JSON 的数据,因为 JSON 数据会自动转换为一个 JavaScript 对象,但不将其分配给变量或者传递给函数,我们也无法拿来使用。
因此,我们可以在请求中提供一个回调函数(被作为参数传递的函数,等同于一般函数),然后通过服务器返回这个函数,并将要返回的 JSON 数据作为函数的参数一同返回,这样<script>
标签在解析并执行返回内容是就会自动调用这个函数。示例代码如下:
<script src="http://localhost:8081/test.php?callback=showJsonData"></script>
服务器 http://localhost:8081/ 的完整代码如下所示:
<?php$data = array('name'=>'一百减一是零', 'url'=>'https://blog.csdn.net/weixin_59383491?spm=1000.2115.3001.5343'); // 定义一个数组,其中包含要返回的内容$callback = $_GET['callback']; // 接收请求中的回调函数echo $callback."(".json_encode($data).")"; // 将上面的数组转换为 JSON 格式,然后拼接到函数中,作为函数的参数,返回给前端return; // 阻止程序向下继续运行
?>
网站 localhost:8080 的完整代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>JavaScript</title>
</head>
<body><script>function showJsonData(data){console.log(data);}</script><script src="http://localhost:8081/test.php?callback=showJsonData"></script>
</body>
</html>
运行结果
{name: '一百减一是零', url: '一百减一是零-CSDN博客'}
总结
通过 JSONP,您可以避开浏览器的同源策略,进行跨域请求。JSONP 是利用 HTML 标签的 src 属性引用资源不受同源策影响的特性来实现的,实现步骤如下:
- 在请求地址中拼接一个回调函数,得到一个新的地址,将这个新地址赋值给 <script> 标签的 src 属性;
- 服务器接收这个回调函数,并向函数中注入参数,然后以字符串的形式返回这个函数以及其中的参数;
- <script> 在接收到返回内容后,会将内容当作是一段 JavaScript 代码,自动执行。
注意:服务器返回的内容,必须是一段可执行的 JavaScript 代码,不能是其它内容。
创作不易,谢谢各位看官大佬的一键三连。