【问题标题】:jQuery.parseJSON throws “Invalid JSON” error due to escaped single quote in JSON由于 JSON 中的转义单引号,jQuery.parseJSON 抛出“Invalid JSON”错误
【发布时间】:2011-01-17 12:52:19
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: javascript jquery json


    【解决方案1】:

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


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


    Douglas Crockford 没有具体说明为什么 JSON 规范不允许在字符串中转义单引号。然而,在Appendix E of JavaScript: The Good Parts 讨论 JSON 时,他写道:

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

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


    再深入一点,Crockford 的 org.json 为 Java 实现的 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 也不接受。

    【讨论】:

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

    如果您需要在字符串中使用单引号,因为规范未定义 \',请使用 \u0027,所有这些都使用 http://www.utf8-chartable.de/

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

    【讨论】:

    • 没有。只需使用一个普通的单引号。
    • 有时,使用 unicode 比使用大量反引号更容易。尤其是在交替反引号内时。
    • 为什么需要反引号?如果你有一个像 "foo 'bar'" 这样的字符串,那么你只需要不转义单引号。
    • 正是我想要的。我正在尝试将 json 字符串作为 js 字符串 var 写入页面并将其括在单引号中,并且只要属性值中有单引号,它就会提前终止。现在,我只需在后面的代码中执行 json.Replace("'", "\u0027") ,然后再将其写入页面。
    • @Zack 您不应该用引号将 JSON 括起来。如果您需要现有 JSON 字符串中的字符串,只需再次对其进行字符串化。在PHP中,这将是var jsonEncodedAsString = <?= json_encode(myEncodedJson) ?>,其中myEncodedJson是先前json_encode的结果,这将负责转义你的单引号,实际上,它只会输出一个用双引号括起来的大字符串,所以单引号不会被转义,但双引号会。
    【解决方案3】:

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

    我正在使用 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 解释器“吃掉”,留下一个以 \"");根据规范,json 字符串必须使用双引号,但 javascript 不在乎,所以,你要么有一个单引号 javascript 字符串,要么有一个双引号,但如果你使用后者,你必须让它们转义所有在字符串中使用双引号。
    【解决方案4】:

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

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

    当你得到包含单引号的值时

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

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

    【讨论】:

    • 但是在将单引号作为 JSON 字符串的一部分传递时,不需要对其进行转义...
    【解决方案5】:

    使用 CakePHP 使用 PHP 的原生 json_encode 输出 JavaScript 脚本块时遇到了类似问题。 $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))."' );"); ?>
    

    【讨论】:

      【解决方案6】:

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

      我最终要做的是在 stringify() 方法调用后使用正则表达式将单引号 ' 替换为代码 &amp;#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.
      

      【讨论】:

        【解决方案7】:

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

        唯一引起我注意的是转义撇号 (\')。鉴于您确实应该使用双引号,因此无需转义单引号。我无法检查这是否确实是您的 jQuery 错误的原因,因为我自己还没有更新到 1.4.1 版。

        【讨论】:

        • 我使用 PHP 中的一个库来生成 JSON 对象 - 有点想把它写下来。感谢您指出这一点。
        猜你喜欢
        • 2012-05-07
        • 2017-07-24
        • 2019-10-14
        • 2021-08-16
        • 2011-05-12
        • 2012-12-30
        • 2017-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多