为什么JSON结果有可能是布尔值而不是对象或数组?

7

来自JSON网站:

JSON构建在两个结构之上:

  • 名称/值对的集合。在各种编程语言中,这可以表示为对象、记录、结构体、字典、哈希表、关联数组等。
  • 有序值列表。在大多数编程语言中,这可以表示为数组、向量、列表或序列。

现在我有一个返回布尔值的示例服务(这是使用PHP编写的,但它可以是任何服务器端语言):

<?php
header('Content-Type: application/json');
echo 'true';
exit;

当使用ajax请求此页面时(例如使用jQuery):

$.ajax({
    url: 'service.php',
    dataType: 'json',
    success: function (data) {
        console.log(data);
        console.log(typeof data);
    }
});

结果将是:
-> true
-> boolean

我的问题是为什么可以将布尔值作为JSON返回。这不会与JSON定义相冲突吗?


此外

此外,我可以在我的服务中返回数字字符串

<?php
header('Content-Type: application/json');
echo '2013';
exit;

结果是:

-> 2013
-> number

对于字符串操作:

<?php
header('Content-Type: application/json');
echo '"What is going on?"';
exit;

结果是:

-> What is going on?
-> string

1
它以JSON格式返回,以允许跨站点AJAX请求。 - Jordan Doyle
如果你只能返回数组或对象,那么这些集合的内容会是什么?最终你需要标量对象作为叶子节点。 - Barmar
@Barmar - 根据RFC,“JSON文本”只能是数组或对象。但是,在该数组或对象内部,您可以使用任何其他JSON数据类型。 - Michael Geary
相关问题,如非重复,请参考:https://dev59.com/5WMl5IYBdhLWcg3wa2bW - GSerg
2个回答

9

您是正确的,有效的JSON文本只能是对象或数组。我在2009年向道格拉斯·克罗克福德询问过这个问题,他确认了这一点,并表示“严格来说,它是对象 | 数组,就像RFC中所述。”

JSON RFC在第2节中指定了这一点:

A JSON text is a serialized object or array.

JSON-text = object / array
原始的JSON语法在json.org上列出,但它并没有清楚地表明哪些类型可以用作“JSON文本”——一个完整的有效的JSON片段。它定义了所有的JSON类型,但并没有说明这些类型中哪些可以用作"JSON text"。
这就是我询问Doug的原因,他把我引荐到RFC。不幸的是,他没有跟进我的建议更新json.org以澄清这一点。
可能正因为这种混淆,许多JSON库会愉快地创建和解析(无效的)JSON字符串、数字、布尔值等,即使那些并不是真正有效的JSON。
一些JSON解析器则更加严格。例如,jsonlint.com会拒绝像101"abc"true这样的JSON文本。它只接受对象或数组。
如果你只是为自己的Web应用程序生成JSON数据,这种区别可能并不重要。毕竟,JSON.parse()很乐意解析它,并且在所有浏览器中都适用。
但如果你为其他人生成JSON,这一点就很重要了。在那里,你应该更严格地遵循标准。
我建议即使在您自己的应用程序中也遵循此建议,部分原因是有实际的好处:通过发送对象而不是裸字符串,您内置了一个位置来添加更多信息(如果您需要),以对象的形式添加其他属性。
沿着这些线路,当我定义JSON API时,我从不在最高级别使用数组。如果我拥有某种项目的数组,我仍然将其包装在对象中:
{
    "items": [
        ...
    ]
}

这部分原因在于:如果我以后想要添加其他内容到响应中,将顶层设为对象可以很容易地实现而不会干扰任何现有的客户端代码。

更重要的是,JSON数组可能存在安全风险。(我认为该风险仅影响使用eval()Function构造函数来解析JSON,因此您可以使用JSON.parse()安全解析,但我不能100%确定。)


1
JSON数组的安全风险出现在CSRF上下文中,其中浏览器本身解析JSON - 通过脚本标记获取,跨域使用用户会话! - 作为JS。也就是说,安全风险不是针对脚本本身[假设它获取同源数据],而是针对数据的隐私。[或者也许应该说风险“曾经”存在...我认为浏览器现在已经关闭了这样的副作用。] - natevw
@natevw - JSON数组漏洞与数据隐私无关,它意味着数据本身作为JSON数组也是有效的JavaScript,浏览器可能会执行实际代码而不是反序列化。这就是为什么永远不要将JSON数组作为根数据返回,并优先选择一个带有“items”键的对象的主要原因。 - Adrian Crețu
@AdrianCrețu 请查看链接中的讨论。由于JSON数组是有效的JavaScript,因此存在(曾经存在?)通过CORS绕过的隐私风险。这个链接(来自其他问答评论)直接解释了大部分内容:https://haacked.com/archive/2009/06/25/json-hijacking.aspx/ - natevw
@AdrianCrețu...更不用说,如果您不信任服务器提供“安全”数组,那么您也不应该信任它处理您对对象的“偏好”。问题在于跨域隐私(数组从用户在您的域上的会话泄漏到恶意域),而不是不受信任的数据。 - natevw
@natevw - 我在某种程度上同意你的观点。然而,一个 JSON 对象本身并不是有效的 JavaScript 代码,而数组则是。这是一个很大的区别,也是微软自己将所有 JSON 代理数据包装在一些库中嵌入到 JSON 对象中的主要原因,无论你喜欢与否 :) - Adrian Crețu

1
注意,迈克尔·吉里的答案已经过时,因为2013年的rfc7158不再限制JSON文本只能是数组或对象。当前的RFC https://www.rfc-editor.org/rfc/rfc8259 表示:
一个JSON文本是一个序列化的值。请注意,先前的某些JSON规范将JSON文本限制为对象或数组。在需要JSON文本的情况下仅生成对象或数组的实现将是互操作的,因为所有实现都将接受这些符合JSON规范的文本。

它继续确认JSON值是:对象、数组、字符串、数字、true、false、null。 - Josh.F
另外,我刚刚发现这个链接再次证实了RFC已经改变:https://dev59.com/5WMl5IYBdhLWcg3wa2bW?noredirect=1&lq=1 - Josh.F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接