ChatGPT解决这个技术问题 Extra ChatGPT

JSON 字符编码 - 浏览器是否很好地支持 UTF-8 或者我应该使用数字转义序列?

我正在编写一个使用 json 来表示其资源的 web 服务,但我对编码 json 的最佳方式感到有点困惑。阅读 json rfc (http://www.ietf.org/rfc/rfc4627.txt),很明显首选编码是 utf-8。但是 rfc 还描述了一种用于指定字符的字符串转义机制。我认为这通常用于转义非 ascii 字符,从而使生成的 utf-8 有效 ascii。

因此,假设我有一个 json 字符串,其中包含非 ascii 的 unicode 字符(代码点)。我的网络服务应该只是 utf-8 编码并返回它,还是应该转义所有那些非 ascii 字符并返回纯 ascii?

我希望浏览器能够使用 jsonp 或 eval 执行结果。这会影响决定吗?我缺乏对各种浏览器对 utf-8 的 javascript 支持的了解。

编辑:我想澄清一下,我对如何编码结果的主要关注实际上是浏览器对结果的处理。我读到的内容表明,特别是在使用 JSONP 时,浏览器可能对编码很敏感。我还没有找到关于这个主题的任何真正好的信息,所以我必须开始做一些测试来看看会发生什么。理想情况下,我只想转义那些需要的几个字符,只对结果进行 utf-8 编码。


t
thomasrutter

JSON 规范要求解码器支持 UTF-8。因此,所有 JSON 解码器都可以像处理数字转义序列一样处理 UTF-8。 Javascript 解释器也是如此,这意味着 JSONP 也将处理 UTF-8 编码的 JSON。

JSON 编码器使用数字转义序列的能力只是为您提供了更多选择。您可以选择数字转义序列的一个原因是,如果您的编码器和预期解码器之间的传输机制不是二进制安全的。

您可能要使用数字转义序列的另一个原因是为了防止某些字符出现在流中,例如 <&",如果 JSON 代码没有转义,它们可能会被解释为 HTML 序列HTML 或浏览器错误地将其解释为 HTML。这可以防御 HTML 注入或跨站点脚本(注意:某些字符必须在 JSON 中转义,包括 "\)。

一些框架,包括 PHP 的 json_encode()(默认情况下),总是在编码器端为 ASCII 之外的任何字符执行数字转义序列。这是一个主要是不必要的额外步骤,旨在最大限度地与有限的传输机制等兼容。但是,这不应被解释为任何 JSON 解码器都存在 UTF-8 问题的迹象。

所以,我想你可以像这样决定使用哪个:

只需使用 UTF-8,除非您用于在编码器和解码器之间进行存储或传输的任何软件都不是二进制安全的。

否则,使用数字转义序列。


“所有 JSON 解码器都可以处理 UTF-8” 虽然浏览器确实如此,但仅仅因为标准要求它并不意味着所有软件解码 JSON 都支持 UTF-8。
“所有 JSON 解码器都可以处理 UTF-8”字面上是真的。如果某些东西不能接受 UTF-8,那么它就不是 JSON 解码器。它可能类似于 JSON 解码器,但绝对不是。
官方提出的 JSON 模式将 JSON 字符串指定为“一串 Unicode 代码点”。这意味着一串 32 位值。事实上,在 json-schema.org/draft/2019-09/json-schema-core.html 中甚至没有提到 UTF-8。
@DavidSpector 错误文档-您正在查看媒体类型应用程序/模式+json 的提案,这不是定义 JSON 的地方。在提到编码时,它表示架构的编码与 JSON 中的编码相同,并在 tools.ietf.org/html/rfc8259 处引用 JSON 规范,其中定义 JSON 必须在任何时候在封闭生态系统之外使用时使用 UTF-8。
谢谢你的纠正!当我看到“一串 Unicode 代码点”时我惊慌失措,因为这会倒退到固定长度的字符。
T
Tim Tisdall

我在那里遇到了问题。当我使用像“é”这样的字符对字符串进行 JSON 编码时,每个浏览器都会返回相同的“é”,除了 IE 会返回“\u00e9”。

然后使用 PHP json_decode(),如果找到“é”,它将失败,所以对于 Firefox、Opera、Safari 和 Chrome,我必须在 json_decode() 之前调用 utf8_encode()。

注意:在我的测试中,IE 和 Firefox 使用它们的原生 JSON 对象,其他浏览器使用 json2.js。


可能您的意思是 utf8_encode()php.net/manual/en/function.utf8-encode.php
如果 IE 无法对其进行解码,那么这就是您使用的任何 JSON 解码器中的一个错误。所有 JSON 解码器都必须成功解码编码形式,否则它们就不是 JSON 解码器。至于您对 é 未转义的 json_decode() 的问题,您输入的文本可能不是 UTF-8。 JSON 解码器总是假定 UTF-8,即使是 PHP 实现,即使 PHP 在许多其他函数中通常不假定 UTF-8。还有其他字符编码可以包括未转义的 é 并且在屏幕上看起来相同,但它们不是 UTF-8。以 \uXXXX 形式编码是一种解决方法。
只是说:JSON 可以合法地采用任何 Unicode 编码(UTF-8、UTF-16 BE/LE、UTF32 BE/LE,有或没有字节顺序标记)。由于 ASCII 是 UTF-8 的一个子集,它也可以是 ASCII。例如,解析器是否接受 UTF-32,我不知道。
这是正确的,解析器不需要支持 UTF-8 以外的任何东西。来自规范:“JSON 文本应以 UTF-8、UTF-16 或 UTF-32 编码。默认编码为 UTF-8,并且以 UTF-8 编码的 JSON 文本在某种意义上是可互操作的被最大实现数成功读取;有许多实现无法成功读取其他编码(例如 UTF-16 和 UTF-32)的文本。实现不能在 JSON 文本的开头添加字节顺序标记。 "
@thomasrutter 您引用的规范是旧的。 current spec 说:“在不属于封闭生态系统的系统之间交换的 JSON 文本必须使用 UTF-8 编码。以前的 JSON 规范在传输 JSON 文本时不要求使用 UTF-8。但是, 绝大多数基于 JSON 的软件实现都选择使用 UTF-8 编码,在某种程度上它是实现互操作性的唯一编码。实现不得在开头添加字节顺序标记 (U+FEFF)网络传输的 JSON 文本。"
c
chaos

ASCII 不在其中了。使用 UTF-8 编码意味着您没有使用 ASCII 编码。你应该使用转义机制是 RFC 所说的:

除了必须转义的字符外,所有 Unicode 字符都可以放在引号内:引号、反斜线和控制字符(U+0000 到 U+001F)


如果阅读您提供的报价,您会发现您不需要转义所有 unicode 字符,只需转义一些特殊字符。但是您需要对结果进行编码(最好使用 utf-8)。所以问题是:“如果你是 utf-8 编码,为什么还要转义普通的 unicode 字符”。
此外,ascii 编码的字符串是 utf-8 的纯子集。如果我对所有非 ascii 字符使用 json 的转义,结果是 ascii - 因此是 utf-8。各种 json 库(如 python simplejson)具有强制 ascii 结果的模式。我想是有原因的,比如在浏览器中执行。
当您费心转义普通 unicode 字符时,它们是元字符的上下文,如字符串。 (我引用的 RFC 块是关于字符串的;抱歉,不清楚。)你不需要一直做 ASCII 输出;我认为这更适合使用损坏的浏览器进行调试。
T
Tobi Nary

我面临着同样的问题。这个对我有用。请检查这个。

json_encode($array,JSON_UNESCAPED_UNICODE);

需要注意的是,上面是 PHP,因为这个问题绝不是 PHP 特定的,只讨论可能不使用 PHP 的 Web 服务(因为我们的老读者可能还记得......)
C
Community

阅读 json rfc (http://www.ietf.org/rfc/rfc4627.txt) 很明显首选编码是 utf-8。

仅供参考,RFC 4627 不再是官方 JSON 规范。它在 2014 年被 RFC 7159 淘汰,然后在 2017 年被当前规范的 RFC 8259 淘汰。

RFC 8259 指出:

8.1。在不属于封闭生态系统的系统之间交换的字符编码 JSON 文本必须使用 UTF-8 [RFC3629] 进行编码。以前的 JSON 规范没有要求在传输 JSON 文本时使用 UTF-8。然而,绝大多数基于 JSON 的软件实现都选择使用 UTF-8 编码,以至于它是唯一实现互操作性的编码。实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (U+FEFF)。为了互操作性,解析 JSON 文本的实现可能会忽略字节顺序标记的存在,而不是将其视为错误。


P
Paul Smith

我对 é char 也有类似的问题...我认为“您输入的文本可能不是 UTF-8”的评论可能接近此处的标记。我有一种感觉,在我意识到并更改为 utf8 之前,我的实例中的默认排序规则是别的东西......问题是数据已经存在,所以不确定它是否在我更改数据时转换了数据,在 mysql 中显示正常工作台。最终结果是php不会对数据进行json编码,只是返回false。无论您使用什么浏览器作为导致我的问题的服务器,如果存在此字符,php 将不会将数据解析为 utf8。就像我说的不确定是由于在数据出现后将架构转换为 utf8 还是只是一个 php 错误。在这种情况下使用 json_encode(utf8_encode($string));