由于 JSON 中的单引号被转义,jQuery.parseJSON 抛出“Invalid JSON”错误

IT技术 javascript jquery json
2021-02-01 15:52:19

我正在向我的服务器发出请求jQuery.post(),我的服务器正在返回 JSON 对象(如{ "var": "value", ... })。但是,如果任何值包含单引号(正确转义如\'),jQuery 将无法解析其他有效的 JSON 字符串。这是我的意思的一个例子(在 Chrome 的控制台中完成):

data = "{ \"status\": \"success\", \"newHtml\": \"Hello \\\'x\" }";
eval("x = " + data); // { newHtml: "Hello 'x", status: "success" }

$.parseJSON(data); // Invalid JSON: { "status": "success", "newHtml": "Hello \'x" }

这是正常的吗?有没有办法通过 JSON 正确传递单引号?

6个回答

根据JSON 网站上的状态机图,只允许转义双引号字符,不允许单引号。单引号字符不需要转义:

http://www.json.org/string.gif


更新- 感兴趣的人的更多信息:


Douglas Crockford 没有具体说明为什么 JSON 规范不允许在字符串中使用转义单引号。然而,在他在JavaScript 的附录 E:好的部分中讨论 JSON 时,他写道:

JSON 的设计目标是最小化、可移植、文本化和 JavaScript 的一个子集。为了互操作,我们需要达成的共识越少,我们就越容易进行互操作。

因此,也许他决定只允许使用双引号定义字符串,因为这是所有 JSON 实现都必须同意的少一条规则。因此,字符串中的单引号字符不可能意外终止字符串,因为根据定义,字符串只能由双引号字符终止。因此,在正式规范中不需要允许转义单引号字符。


深入挖掘一点,Crockford 的org.json JSON for Java 实现更被允许,并且确实允许使用单引号字符:

toString 方法生成的文本严格符合 JSON 语法规则。建设者在他们接受的文本中更加宽容:

...

  • 字符串可以用 '(单引号)引用。

JSONTokener源代码证实了这一点nextString方法接受转义的单引号字符并将它们视为双引号字符:

public String nextString(char quote) throws JSONException {
    char c;
    StringBuffer sb = new StringBuffer();
    for (;;) {
        c = next();
        switch (c) {

        ...

        case '\\':
            c = this.next();
            switch (c) {

            ...

            case '"':
            case '\'':
            case '\\':
            case '/':
                sb.append(c);
                break;
        ...

该方法的顶部是一条信息丰富的注释:

正式的 JSON 格式不允许单引号中的字符串,但允许实现接受它们。

所以一些实现会接受单引号 - 但你不应该依赖于此。许多流行的实现在这方面非常严格,将拒绝包含单引号字符串和/或转义单引号的 JSON。


最后将其与原始问题联系起来,jQuery.parseJSON首先尝试使用浏览器的本机 JSON 解析器或加载的库,如适用的json2.js(旁注是 jQuery 逻辑所基于的库,如果JSON未定义) . 因此 jQuery 只能与底层实现一样宽松:

parseJSON: function( data ) {
    ...

    // Attempt to parse using the native JSON parser first
    if ( window.JSON && window.JSON.parse ) {
        return window.JSON.parse( data );
    }

    ...

    jQuery.error( "Invalid JSON: " + data );
},

据我所知,这些实现只遵守官方的 JSON 规范,不接受单引号,因此 jQuery 也不接受。

@AdrienBe - 有趣...但他们是否意味着任何字符都可以转义,如果它由 4 个十六进制数字组成?根据上面的状态图和 RFC 第 7 节中的状态图,\'仍然不允许对所写的单引号进行转义如果 RFC 在这一点上更明确,那就太好了。
2021-03-11 15:52:19
@JustinEthier 正如这个答案stackoverflow.com/a/25491642/759452所指出的,JSON 规范tools.ietf.org/html/rfc7159Any character may be escaped,这可以解释为什么某些实现会允许转义单引号。
2021-03-18 15:52:19
更新:: JQuery 在传递 JSON 时非常严格。如果你尝试 alert($.parseJSON("[\"Ciao\\'\"]")); 由于贾斯汀的报道,它不起作用
2021-03-19 15:52:19
@DuncanJones - 这篇文章可能会提供有关为什么没有浏览器遵循 JSON 原则的见解joelonsoftware.com/items/2008/03/17.html
2021-04-02 15:52:19
Crockford 的 org.json 对 Java 的 JSON 实现更被允许,并且确实允许使用单引号字符” # 这只是一个很好的做法:健壮性原则
2021-04-09 15:52:19

如果你需要一个字符串的单引号里面,因为\”是由规范中定义,使用\u0027http://www.utf8-chartable.de/为所有这些

编辑:请原谅我在评论中滥用反引号这个词。我的意思是反斜杠。我的观点是,如果您在其他字符串中嵌套了字符串,我认为使用 unicode 而不是大量反斜杠来转义单引号会更有用和可读性更高。如果您不是嵌套的,那么在其中放置一个简单的旧引用确实更容易。

为什么需要反引号?如果您有一个像“foo 'bar'”这样的字符串,那么您只需将单引号保留为未转义即可。
2021-03-14 15:52:19
有时,使用 unicode 比使用大量反引号更容易。特别是在交替反引号内时。
2021-03-20 15:52:19
正是我要找的。我正在尝试将 json 字符串作为 js 字符串 var 写入页面并将其括在单引号中,并且只要属性值中有单引号,它就会提前终止。现在我只是在将代码写入页面之前在后面的代码中执行 json.Replace("'", "\u0027") 。
2021-03-24 15:52:19
@Zack 您不应该用引号将 JSON 括起来。如果您需要现有 JSON 字符串中的字符串,只需再次将其字符串化。在PHP中,这将是var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>其中myEncodedJson的一个先前的结果,json_encode这将需要你的逃逸单引号的护理,其实,它只是输出一些大的字符串双引号括起来,所以单引号不会逃过一劫,但双引号将要。
2021-03-24 15:52:19
不。只需使用简单的单引号。
2021-03-30 15:52:19

我明白问题出在哪里,当我查看规范时,很明显应该正确解析未转义的单引号。

我正在使用 jquery 的 jQuery.parseJSON 函数来解析 JSON 字符串,但是当使用 json_encode 准备的数据中存在单引号时,仍然出现解析错误。

我的实现中是否有一个错误,看起来像这样(PHP - 服务器端):

$data = array();

$elem = array();
$elem['name'] = 'Erik';
$elem['position'] = 'PHP Programmer';
$data[] = json_encode($elem);

$elem = array();
$elem['name'] = 'Carl';
$elem['position'] = 'C Programmer';
$data[] = json_encode($elem);

$jsonString = "[" . implode(", ", $data) . "]";

最后一步是我将 JSON 编码的字符串存储到一个 JS 变量中:

<script type="text/javascript">
employees = jQuery.parseJSON('<?=$marker; ?>');
</script>

如果我使用 "" 而不是 '' 它仍然会引发错误。

解决方案:

唯一对我有用的是使用位掩码 JSON_HEX_APOS 像这样转换单引号:

json_encode($tmp, JSON_HEX_APOS);

有没有其他方法可以解决这个问题?我的代码是错误的还是写得不好?

谢谢

'<?=$标记;?>' 这不是有效的 json。周围的引号被 javascript 解释器“吃掉”,留下一个以 < 开头的字符串......你真正想尝试的是以下任一: jQuery.parseJSON('"<?=$marker; ?>" '); jQuery.parseJSON("\"<?=$marker; ?>\""); 根据规范,json 字符串必须使用双引号,但 javascript 不在乎,因此,您可以使用单引号 javascript 字符串或双引号,但是如果使用后者,则必须让它们转义所有在字符串中使用双引号。
2021-04-02 15:52:19

当您在查询中发送单引号时

empid = " T'via"
empid =escape(empid)

当您获得包含单引号的值时

var xxx  = request.QueryString("empid")
xxx= unscape(xxx)

如果要在查询中搜索/插入包含单引号的值 xxx=Replace(empid,"'","''")

但是当将它作为 JSON 字符串的一部分传递时,不需要转义单引号......
2021-04-02 15:52:19

使用 CakePHP 使用 PHP 的本机json_encode. $contractorCompanies包含具有单引号的值,如上所述,并且预期json_encode($contractorCompanies)不会转义它们,因为它是有效的 JSON。

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".(json_encode($contractorCompanies)."' );"); ?>

通过在 JSON 编码的字符串周围添加 addlashes() ,您然后转义引号允许 Cake / PHP 将正确的 javascript 回显到浏览器。JS 错误消失。

<?php $this->Html->scriptBlock("var contractorCompanies = jQuery.parseJSON( '".addslashes(json_encode($contractorCompanies))."' );"); ?>