jQuery.parseJSON由于JSON中的单引号转义而引发“无效的JSON”错误


202

我正在使用向服务器发出请求,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正确传递单引号吗?

Answers:


325

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

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


更新 -有兴趣者的更多信息:


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

JSON的设计目标是最小化,可移植,文本化以及JavaScript的子集。我们需要达成共识以进行互操作的次数越少,我们就越容易进行互操作。

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


深入研究一下,Crockford的JSON for Java 的org.json实现更为允许,并且确实允许使用单引号字符:

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也是如此。


4
更新::粘贴JSON时,JQuery的限制非常严格。如果您尝试alert($。parseJSON(“ [\” Ciao \\'\“]”)); 由于贾斯汀的报道而无法正常工作
daitangio,2010年

2
Crockford的JSON for Java的org.json实现更被允许,并且允许单引号字符。 ”#这只是一个好习惯:稳健性原则
Duncan Jones

1
@DuncanJones-本文可能提供有关为什么没有一个浏览器似乎遵循JSON原则的见解
Justin Ethier

1
JSON规范tools.ietf.org/html/rfc7159指出,此答案stackoverflow.com/a/25491642/759452指出@JustinEthierAny character may be escaped,这可以解释为什么某些实现将单引号转义。
Adrien Be

1
@AdrienBe-有趣...但是,这是否意味着如果任何字符由4个十六进制数字组成,则可以将其转义?根据上面的状态图和RFC第7节中的状态图,\'仍然不允许转义书写的单引号。如果在这一点上RFC更明确,那就太好了。
贾斯汀·埃斯蒂尔2014年

15

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

编辑:请原谅我在评论中误用了反引号。我的意思是反斜杠。我的意思是,如果您在其他字符串中嵌套了字符串,则我认为使用unicode而不是大量的反斜杠来转义单引号可能更为有用和可读。但是,如果您不嵌套,只在其中添加简单的旧引号确实会更容易。


29
不,只需使用一个普通的单引号即可。
杰夫·考夫曼

有时候,使用unicode比处理大量反向标记要容易得多。特别是在内部交替倒转时。
2012年

3
为什么需要反引号?如果您有类似“ foo'bar'”的字符串,则只需保留单引号不转义。
Jeff Kaufman 2012年

3
正是我想要的。我试图将json字符串作为js字符串var写到页面上,并将其用单引号引起来,并且只要属性值中包含单引号,它就会提前终止。现在,在将代码写入页面之前,我只需在后面的代码中执行json.Replace(“'”,“ \ u0027”)。
扎克2014年

@Zack您不应将JSON引号引起来。如果您需要现有JSON字符串中的字符串,请再次对其进行字符串化。在PHP中,这将是var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>其中myEncodedJson的一个先前的结果,json_encode这将需要你的逃逸单引号的护理,其实,它只是输出一些大的字符串双引号括起来,所以单引号不会逃过一劫,但双引号将。
Juan Mendes 2015年

5

我了解问题出在哪里,当我查看规格时,很清楚应该正确解析未转义的单引号。

我正在使用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);

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

谢谢


'<?= $ marker; ?>'这不是有效的json。周围的引号由javascript解释器“吞噬”,剩下一个以<...开头的字符串,您真正想要尝试的是以下任意一种:jQuery.parseJSON('“ <?= $ marker;?>” '); jQuery.parseJSON(“ \” <?= $ marker;?> \“”); 根据规范,json字符串必须使用双引号,但是javascript不在乎,因此,您可以使用单引号的javascript字符串,也可以使用双引号,但是如果使用后者,则必须使它们转义所有在字符串中使用双引号。
克里斯·科格登

3

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

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

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

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

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


1
但是,当将其作为JSON字符串的一部分传递时,无需转义单引号...
Justin Ethier 2013年

2

使用CakePHP使用PHP的native来输出JavaScript脚本块,引发了类似的问题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))."' );"); ?>

1

我试图将XHR请求中的JSON对象保存到HTML5 data- *属性中。我尝试了许多上述解决方案,但均未成功。

我终于结束了自己是在代替单引号'与它的代码&#39;使用字符串化()方法调用下面的方法后,正则表达式:

var productToString = JSON.stringify(productObject);
var quoteReplaced = productToString.replace(/'/g, "&#39;");
var anchor = '<a data-product=\'' + quoteReplaced + '\' href=\'#\'>' + productObject.name + '</a>';
// Here you can use the "anchor" variable to update your DOM element.

0

有趣。您如何在服务器端生成JSON?您是在使用库函数(例如json_encode在PHP中),还是在手动构建JSON字符串?

唯一引起我注意的是转义撇号(\')。就像您确实应该使用双引号一样,您无需转义单引号。我无法检查那是否确实是jQuery错误的原因,因为我本人尚未更新至1.4.1版。


我在PHP中使用一个库来生成JSON对象-有点想写下来了。感谢您指出了这一点。
ErikČerpnjak2015年
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.