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


89

我正在编写一个使用json表示其资源的web服务,并且我在思考对json进行编码的最佳方法有些困惑。阅读json rfc(http://www.ietf.org/rfc/rfc4627.txt)显然,首选编码是utf-8。但是RFC还描述了用于指定字符的字符串转义机制。我认为这通常用于转义非ASCII字符,从而使生成的utf-8有效ASCII。

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

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

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

Answers:


88

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

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

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

一些框架,包括PHP的JSON实现,总是在编码器端对ASCII以外的任何字符执行数字转义序列。这旨在与有限的传输机制等实现最大的兼容性。但是,这不应解释为JSON解码器在UTF-8上存在问题的指示。

因此,我想您只是可以决定使用哪种方法:

  • 除非您的编码器和解码器之间的存储或传输方法不是二进制安全的,否则只需使用UTF-8。

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


1
“所有JSON解码器都可以处理UTF-8”尽管浏览器确实如此,但这仅仅是因为该标准要求并不意味着所有解码JSON的软件都支持UTF-8。
Michael Mior

7
“所有JSON解码器都可以处理UTF-8”确实是正确的。如果某些东西不能接受UTF-8,则它不是JSON解码器。它可能类似于JSON解码器,但绝对不是一个。
thomasrutter

我想这取决于您使用的JSON解码器的定义,但很公平:)
Michael Mior

RFC 8259将UTF-8支持指定为强制性的原因是,这已成为世界范围的标准。以前的过时规范将字符串定义为Unicode,但未指定编码方式。无论如何,都是在UTF-8上标准化的实现,而更新的规范反映了这一点。
thomasrutter

据我所知,对于任何特定软件,该RFC中均未将UTF-8支持指定为强制性的。关于UTF-8的唯一提及是,必须将其用作在封闭系统之外交换的JSON的编码。这并不意味着所有JSON解码器(RFC中未使用的语言)都必须支持UTF-8。
Michael Mior

17

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

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

注意:在我的测试中,IE和Firefox使用的是本机JSON对象,其他浏览器使用的是json2.js。


10
可能是您的意思utf8_encode()php.net/manual/en/function.utf8
Binyamin

4
如果IE无法解码,则说明您使用的JSON解码器均存在错误。所有JSON解码器都必须成功解码编码形式,否则它们不是JSON解码器。至于使用é而不转义json_decode()的问题,您输入的文本可能不是UTF-8。JSON解码器始终假定UTF-8,即使是PHP实现,即使PHP在许多其他函数中通常不假定UTF-8也是如此。还有其他一些字符编码,其中可以包含é非转义字符,并且在屏幕上看起来相同,但不是UTF-8。以\ uXXXX格式编码是解决此问题的方法。
thomasrutter

只是说:JSON可以合法地采用任何Unicode编码(UTF-8,UTF-16 BE / LE,UTF32 BE / LE,带有或不带有字节顺序标记)。而且由于ASCII是UTF-8的子集,所以它也可以采用ASCII。我不知道解析器是否接受UTF-32。
gnasher729'9

1
没错,解析器不需要支持UTF-8之外的任何其他功能。根据规范:“ JSON文本应以UTF-8,UTF-16或UTF-32进行编码。默认编码为UTF-8,并且以UTF-8编码的JSON文本可以互操作,可以通过最大数量的实现成功读取;有许多实现无法成功读取其他编码的文本(例如UTF-16和UTF-32),实现不得在JSON文本的开头添加字节顺序标记。 ”
thomasrutter

@thomasrutter您引用的规范很旧。在当前的规范说:“这是不是一个封闭的生态系统,必须使用UTF-8编码的系统间JSON文本交换JSON的早期规格传输JSON文本时没有要求使用UTF-8。然而,绝大部分。基于JSON的软件实现中,有一部分选择了使用UTF-8编码,因为它是实现互操作性的唯一编码。实现不得在网络传输的开头添加字节顺序标记(U + FEFF) JSON文本。
Remy Lebeau,

12

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

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


1
如果阅读了您提供的那句话,您将看到您不需要转义所有unicode字符,只需转义一些特殊字符。但是您需要对结果进行编码(最好使用utf-8)。因此,问题是:“如果使用utf-8编码,为什么要转义普通的unicode字符”。
schickb

同样,ASCII编码的字符串是utf-8的纯子集。如果我对所有非ascii字符使用json的转义,则结果为ascii-因此为utf-8。各种json库(例如python simplejson)都有强制执行ascii结果的模式。我推测是有原因的,例如可能在浏览器中执行。
schickb

当您麻烦转义普通Unicode字符时,是在它们是元字符的上下文中,例如字符串。(我引用的RFC块是关于字符串的;对不起,还不清楚。)您不必一直进行ASCII输出;我认为这更多是用于使用损坏的浏览器进行调试。
混乱

7

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

json_encode($array,JSON_UNESCAPED_UNICODE);

应当指出的是,上面的内容是PHP,因为该问题绝非特定于PHP,而是仅讨论了也可能不使用PHP的Web服务(因为我们的较早读者可能还记得……)
ntninja

1

阅读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文本的实现可以忽略字节顺序标记的存在,而不是将其视为错误。


0

我在échar上也遇到了类似的问题。我认为评论“您正在输入的文字很可能不是UTF-8”可能与此处的文字差不多。我感觉我实例中的默认排序规则是其他事情,直到我意识到并更改为utf8 ...问题是数据已经存在,所以不确定在我更改数据时是否转换了数据,在mysql中显示正常工作台。最终结果是php将不会对数据进行json编码,只会返回false。不管使用哪种浏览器作为服务器导致我的问题,如果存在此字符,php都不会将数据解析为utf8。就像我说不知道是否是由于存在数据后将架构转换为utf8还是仅是PHP错误。在这种情况下使用json_encode(utf8_encode($string));

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.