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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2275359/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:34:29  来源:igfitidea点击:

jQuery.parseJSON throws “Invalid JSON” error due to escaped single quote in JSON

javascriptjqueryjson

提问by Felix

I'm making requests to my server using jQuery.post()and my server is returning JSON objects (like { "var": "value", ... }). However, if any of the values contains a single quote (properly escaped like \'), jQuery fails to parse an otherwise valid JSON string. Here's an example of what I mean (done in Chrome's console):

我正在向我的服务器发出请求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" }

Is this normal? Is there no way to properly pass a single quote via JSON?

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

回答by Justin Ethier

According to the state machine diagram on the JSON website, only escaped double-quote characters are allowed, not single-quotes. Single quote characters do not need to be escaped:

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

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

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


Update- More information for those that are interested:


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



Douglas Crockford does not specifically say why the JSON specification does not allow escaped single quotes within strings. However, during his discussion of JSON in Appendix E of JavaScript: The Good Parts, he writes:

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

JSON's design goals were to be minimal, portable, textual, and a subset of JavaScript. The less we need to agree on in order to interoperate, the more easily we can interoperate.

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

So perhaps he decided to only allow strings to be defined using double-quotes since this is one less rule that all JSON implementations must agree on. As a result, it is impossible for a single quote character within a string to accidentally terminate the string, because by definition a string can only be terminated by a double-quote character. Hence there is no need to allow escaping of a single quote character in the formal specification.

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



再深入一点,克罗克福德的 org.json用于 Java 的 JSON 的org.json实现更被允许,并且does确实允许单引号字符:

The texts produced by the toString methods strictly conform to the JSON syntax rules. The constructors are more forgiving in the texts they will accept:

...

  • Strings may be quoted with ' (single quote).

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

...

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

This is confirmed by the JSONTokenersource code. The nextStringmethod accepts escaped single quote characters and treats them just like double-quote characters:

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;
        ...

At the top of the method is an informative comment:

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

The formal JSON format does not allow strings in single quotes, but an implementation is allowed to accept them.

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

So some implementations will accept single quotes - but you should not rely on this. Many popular implementations are quite restrictive in this regard and will reject JSON that contains single quoted strings and/or escaped single quotes.

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



Finally to tie this back to the original question, jQuery.parseJSONfirst attempts to use the browser's native JSON parser or a loaded library such as json2.jswhere applicable (which on a side note is the library the jQuery logic is based on if JSONis not defined). Thus jQuery can only be as permissive as that underlying implementation:

最后将其与原始问题联系起来,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 );
},

As far as I know these implementations only adhere to the official JSON specification and do not accept single quotes, hence neither does jQuery.

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

回答by slf

If you need a single quote inside of a string, since \' is undefined by the spec, use \u0027see http://www.utf8-chartable.de/for all of them

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

edit: please excuse my misuse of the word backticks in the comments. I meant backslash. My point here is that in the event you have nested strings inside other strings, I think it can be more useful and readable to use unicode instead of lots of backslashes to escape a single quote. If you are not nested however it truly is easier to just put a plain old quote in there.

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

回答by Erik ?erpnjak

I understand where the problem lies and when I look at the specs its clear that unescaped single quotes should be parsed correctly.

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

I am using jquery`s jQuery.parseJSON function to parse the JSON string but still getting the parse error when there is a single quote in the data that is prepared with json_encode.

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

Could it be a mistake in my implementation that looks like this (PHP - server side):

我的实现中是否有一个错误,看起来像这样(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) . "]";

The final step is that I store the JSON encoded string into an JS variable:

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

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

If I use "" instead of '' it still throws an error.

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

SOLUTION:

解决方案:

The only thing that worked for me was to use bitmask JSON_HEX_APOS to convert the single quotes like this:

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

json_encode($tmp, JSON_HEX_APOS);

Is there another way of tackle this issue? Is my code wrong or poorly written?

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

Thanks

谢谢

回答by BehranG BinA

When You are sending a single quote in a query

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

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

When You get the value including a single quote

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

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

If you want to search/ insert the value which includes a single quote in a query xxx=Replace(empid,"'","''")

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

回答by chopstik

Striking a similar issue using CakePHP to output a JavaScript script-block using PHP's native json_encode. $contractorCompaniescontains values that have single quotation marks and as explained above and expected json_encode($contractorCompanies)doesn't escape them because its valid JSON.

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

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

By adding addslashes() around the JSON encoded string you then escape the quotation marks allowing Cake / PHP to echo the correct javascript to the browser. JS errors disappear.

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

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

回答by BoCyrill

I was trying to save a JSON object from a XHR request into a HTML5 data-* attribute. I tried many of above solutions with no success.

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

What I finally end up doing was replacing the single quote 'with it code &#39;using a regex after the stringify() method call the following way:

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

回答by Aistina

Interesting. How are you generating your JSON on the server end? Are you using a library function (such as json_encodein PHP), or are you building the JSON string by hand?

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

The only thing that grabs my attention is the escape apostrophe (\'). Seeing as you're using double quotes, as you indeed should, there is no need to escape single quotes. I can't check if that is indeed the cause for your jQuery error, as I haven't updated to version 1.4.1 myself yet.

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