什么是 JSON 以及如何使用它?

已发表: 2022-08-14
覆盖在计算机显示器上的“JSON”文本图像
玛丽亚沃诺特纳/Shutterstock.com

JSON(JavaScript Object Notation)是一种用于表示结构化数据的标准化格式。 尽管 JSON 从 JavaScript 编程语言发展而来,但它现在已成为系统间数据交换的普遍方法。 大多数现代 API 接受 JSON 请求并发出 JSON 响应,因此对格式及其功能有很好的工作知识很有用。

在本文中,我们将解释 JSON 是什么,它如何表达不同的数据类型,以及在流行的编程语言中生成和使用它的方式。 我们还将介绍 JSON 的一些限制以及已经出现的替代方案。

JSON基础

JSON 最初是由 Douglas Crockford 设计的,作为一种无状态格式,用于在浏览器和服务器之间进行数据通信。 早在 2000 年代初期,网站开始在初始页面加载后从其服务器异步获取额外数据。 作为从 JavaScript 派生的基于文本的格式,JSON 使在这些应用程序中获取和使用数据变得更加简单。 该规范最终在 2013 年被标准化为 ECMA-404。

JSON 始终作为字符串传输。 这些字符串可以解码为一系列基本数据类型,包括数字、布尔值、数组和对象。 这意味着可以在传输过程中保留对象层次结构和关系,然后在接收端以适合编程环境的方式重新组装。

一个基本的 JSON 示例

这是一篇博文的 JSON 表示:

 {
    “身份证”:1001,
    "title": "什么是 JSON?",
    “作者”: {
        “身份证”:1,
        “名称”:“詹姆斯沃克”
    },
    “标签”:[“api”,“json”,“编程”],
    “已发布”:错误,
    “已发布时间戳”:空
}

此示例演示了所有 JSON 数据类型。 它还说明了 JSON 格式数据的简洁性,这是使其在 API 中使用如此吸引人的特征之一。 此外,与 XML 等更冗长的格式不同,JSON 相对容易按原样阅读。

JSON 数据类型

六种类型的数据可以在 JSON 中原生表示:

  • 字符串——字符串写在双引号之间; 字符可以使用反斜杠进行转义。
  • 数字——数字写成不带引号的数字。 您可以包含一个小数部分来表示一个浮点数。 大多数 JSON 解析实现在不存在小数点时假定为整数。
  • 布尔值 – 支持文字值truefalse
  • Nullnull文字值可用于表示空值或省略值。
  • 数组——数组是用方括号表示的简单列表。 列表中的每个元素都用逗号分隔。 数组可以包含任意数量的项目,并且可以使用所有支持的数据类型。
  • 对象——对象由大括号创建。 它们是键值对的集合,其中键是字符串,用双引号括起来。 每个键都有一个可以采用任何可用数据类型的值。 您可以嵌套对象以创建级联层次结构。 每个值后面必须有一个逗号,表示该键值对的结束。

JSON 解析器会自动将这些数据类型转换为适合其语言的结构。 例如,您不需要手动将id转换为整数。 解析整个 JSON 字符串足以将值映射回其原始数据格式。

语义和验证

在对数据进行编码时,JSON 有一些需要遵守的规则。 不符合语法的字符串将无法被消费者解析。

特别重要的是要注意字符串和对象键周围的引号。 您还必须确保在对象或数组中的每个条目之后使用逗号。 但是,JSON不允许在最后一个条目之后使用尾随逗号——无意中包含一个逗号是导致验证错误的常见原因。 大多数文本编辑器会为您突出显示语法问题,帮助发现错误。

尽管有这些常见的转折点,但 JSON 是最容易手动编写的数据格式之一。 大多数人一旦熟悉了语法,就会发现它既快捷又方便。 总体而言,JSON 往往比 XML 更不容易出错,其中不匹配的开始和结束标记、无效的模式声明和字符编码问题通常会导致问题。

指定 JSON 内容

当 JSON 保存到文件时,通常使用.json扩展名。 JSON 内容具有标准化的 MIME 类型application/json ,尽管出于兼容性原因有时使用text/json 。 现在,您应该依赖application/json来获取AcceptContent-Type HTTP 标头。

大多数使用 JSON 的 API 会将所有内容封装在顶级对象中:

 {
    “错误”:1000
}

但这不是必需的——文字类型作为文件中的顶级节点是有效的,因此以下示例也是有效的 JSON:

 1000 
 真的
 无效的

它们将在您的编程语言中解码为各自的标量。

使用 JSON

大多数编程语言都有内置的 JSON 支持。 下面介绍了如何在一些流行的环境中与 JSON 数据进行交互。

JavaScript

在 JavaScript 中JSON.stringify()JSON.parse()方法用于编码和解码 JSON 字符串:

 常量帖子= {
    编号 1001 
    标题 “什么是 JSON?” ,
    作者 {
        编号 1 
        名称 “詹姆斯沃克”
    }
} ;

常量编码Json = JSON。 字符串化发布 

// {"id": 1001, "title": "什么是 JSON?", ...}
安慰。 日志编码的Json  

常量解码Json = JSON。 解析编码Json  

//詹姆斯沃克
安慰。 日志 decodedJson.author.name   _

PHP

PHP 中的等效函数是json_encode()json_decode()

 $帖子= [
    "id" => 1001 ,
    “标题” => “什么是 JSON?” ,
    “作者” => [
        "id" => 1 ,
        “名字” => “詹姆斯沃克”
    ]
] ;

$encodedJson = json_encode ( $post ) ;

// {"id": 1001, "title": "什么是 JSON?", ...}
回声$encodedJson ;

$decodedJson = json_decode ( $encodedJson , true ) ;

//詹姆斯沃克
echo $decodedJson [ "作者" ] [ "名称" ] ;

Python

Python 提供json.dumps()json.loads()分别进行序列化和反序列化:

 导入json

帖子= {
    “身份证”1001 
    "title" : "什么是 JSON?" ,
    “作者”{
        “身份证”1 
        “名称”“詹姆斯沃克”
    }
}

编码的JSON = json。 转储帖子

# {"id": 1001, "title": "什么是 JSON?", ...}
打印编码的Json 

解码的Json = json。 加载编码的Json 

#詹姆斯沃克
打印 decodedJson [ “作者” ] [ “名称” ] 

红宝石

Ruby 提供JSON.generateJSON.parse

 需要“json”

帖子 = {
    "id" => 1001 ,
    “标题” => “什么是 JSON?” ,
    “作者” => {
        "id" => 1 ,
        “名字” => “詹姆斯沃克”
    }
}

编码的JSON = JSON。 生成发布

# {"id": 1001, "title": "什么是 JSON?", ...}
编码的Json

解码的JSON = JSON。 解析编码的Json 

#詹姆斯沃克
decodedJson [ “作者” ] [ “名称” ]

JSON 限制

JSON 是一种轻量级格式,专注于在数据结构中传达值。 这使得它可以快速解析并且易于使用,但也意味着存在可能导致挫折的缺点。 以下是一些最大的问题。

暂无评论

JSON 数据不能包含评论。 缺少注释会降低清晰度并迫使您将文档放在其他地方。 这可能使 JSON 不适合诸如配置文件之类的情况,在这些情况下修改不频繁并且字段的目的可能不清楚。

没有模式

JSON 不允许您为数据定义模式。 例如,没有办法强制id是必需的整数字段。 这可能会导致无意中出现格式错误的数据结构。

没有参考

字段不能引用数据结构中的其他值。 这通常会导致重复增加文件大小。 回到前面的博客文章示例,您可以有一个博客文章列表,如下所示:

 {
    “帖子”:[
        {
            “身份证”:1001,
            "title": "什么是 JSON?",
            “作者”: {
                “身份证”:1,
                “名称”:“詹姆斯沃克”
            }
        },
        {
            “身份证”:1002,
            "title": "什么是 SaaS?",
            “作者”: {
                “身份证”:1,
                “名称”:“詹姆斯沃克”
            }
        }
    ]
}

两篇文章的作者相同,但与该对象相关的信息必须重复。 在理想情况下,JSON 解析器实现将能够从类似于以下的输入生成上面显示的结构:

 {
    “帖子”:[
        {
            “身份证”:1001,
            "title": "什么是 JSON?",
            “作者”:“{{ .authors.james }}”
        },
        {
            “身份证”:1002,
            "title": "什么是 SaaS?",
            “作者”:“{{ .authors.james }}”
        }
    ],
    “作者”:{
        “詹姆士”: {
            “身份证”:1,
            “名称”:“詹姆斯沃克”
        }
    }
}

目前,标准 JSON 无法做到这一点。

没有高级数据类型

六种支持的数据类型省略了许多常见类型的值。 JSON 本身无法存储日期、时间或地理位置点,因此您需要自行决定此信息的格式。

这会导致不方便的差异和极端情况。 如果您的应用程序将时间戳作为字符串处理,例如2022-07-01T12:00:00+00:00 ,但外部 API 将时间显示为 Unix 纪元后的秒数 – 1657287000 – 您需要记住何时使用每个格式。

JSON 替代品

YAML 是领先的 JSON 替代方案。 它是格式的超集,具有更易于阅读的表示、自定义数据类型和对引用的支持。 它旨在解决与 JSON 相关的大多数可用性挑战。

YAML 已在配置文件以及 DevOps、IaC 和可观察性工具中得到广泛采用。 它很少用作 API 的数据交换格式。 YAML 的相对复杂性意味着它对新手来说不太容易接近。 小的语法错误可能会导致令人困惑的解析失败。

协议缓冲区(protobufs)是另一个新兴的 JSON 竞争者,旨在序列化结构化数据。 Protobuf 具有数据类型声明、必填字段和对大多数主要编程语言的支持。 作为通过网络传输数据的更有效方式,该系统越来越受欢迎。

概括

JSON 是一种基于文本的数据表示格式,可以对六种不同的数据类型进行编码。 JSON 已成为软件开发生态系统的主要内容; 它受到所有主要编程语言的支持,并已成为过去几十年开发的大多数 REST API 的默认选择。

虽然 JSON 的简单性是其受欢迎的一部分,但它也限制了您可以使用该格式实现的目标。 缺乏对模式、注释、对象引用和自定义数据类型的支持意味着一些应用程序会发现它们超出了 JSON 所能提供的范围。 YAML 和 Protobuf 等较年轻的替代方案有助于解决这些挑战,而 XML 仍然是想要定义数据模式且不介意冗长的应用程序的竞争者。