在node.js中出现奇怪的JSON.parse()错误

7

我正在使用node.js通过TCP检索一些字符串化的JSON,并希望解析它。所以我的方法类似于这个。我已经缩短和简化了它,所以您不必了解周围的逻辑。

socket.on("data", function(data) {
    console.log(data.toString());               // Shows the original stringifyed version
    console.log(JSON.parse(data.toString()));   // Doesn't work
});

完整的(美化后)JSON 如下所示。正如您所看到的,没有错误。
{
    "result": "success",
    "source": "chat",
    "success": {
        "message": "test",
        "time": 1331770513,
        "player": "silvinci"
    }
}

但是JSON.parse(data.toString())总是抛出这个愚蠢的错误:

{"result":"success","source":"console","success":{"time":1331762264,"line":"20
^
SyntaxError: Unexpected token {
    at Object.parse (native)
    at Socket.<anonymous> (/home/node/api.js:152:35)    // irrelevant from here on
    at Socket.emit (events.js:67:17)
    at TCP.onread (net.js:347:14)

所以我想:“JSON字符串可能有什么问题。让我们直接尝试一下,不应该起作用。” 惊喜!它起作用了。为什么直接输入字符串可以工作?


2
你真的运行了缩短和简化后的代码吗? - Matthew Flaschen
1
也许流中包含一些奇怪的控制字符... data 是一个字符串还是已经解析的对象(或其他内容)? - Felix Kling
1
@FelixKling 的观点很好。data.toString().charCodeAt(0) 是什么? - Matthew Flaschen
顺便提一下,我注意到 1331770513 没有引号 "",我怀疑这不符合 JSON 标准。 - OCB
@ChinBoon,没问题,因为它是一个数字。 - Matthew Flaschen
显示剩余3条评论
3个回答

17
感谢@Felix Kling,我找到了我的错误。过滤未转义的字符非常重要,特别是在字符串化的JSON之外。我没有这样做,并忽视了在字符串化的JSON之后紧接着的一个不可见的换行符。
这是修复方法:
socket.on("data", function(data) {
    console.log(data.toString());                          // Shows the original stringified version
    console.log(JSON.parse(data.toString().slice(0, -4))); // Trim the sequence "\r\n" off the end of the string
});

请注意,这仅适用于我,因为我有一个非常特殊的情况。服务器始终响应以JSON行结束,并以\r\n结尾 - 不是空格字符,而是反斜杠r和反斜杠n。
由于其他错误,您的代码可能(或可能)失败。但是,在出现解析错误时检查服务器的响应是一个很好的起点。
正如@Zack正确指出的那样,这是一个更一般的修复程序,用于删除不需要的空格:
JSON.parse(data.toString().trim());

3
不了解具体情境,盲目地截断字符串似乎有些危险。或许在切片之前应该添加一个检测被攻击字符的测试。 - MarkHu
在我的情况下,每个响应都以\r\n终止。但是你说得对,所以我附加了一个通知。 - buschtoens
1
如果你发现此问题并且想要一个更一般的解决方案,可以使用以下代码:JSON.parse(data.toString().trim());String.prototype.trim将移除字符串前后的空格。 - Zack
1
@Zack 是的!已经添加到答案中了。 :) - buschtoens

4

我也遇到了类似的问题。为了提供一个更通用的解决方案,这个方法同样适用。它去掉字符串前后的所有空格,因此您不需要进行特定的子字符串长度操作。

JSON.parse(data.trim());

1

不要盲目地删除最后4个字符,建议只删除有问题的字符:

socket.on("data", function(data) {
    console.log(data.toString()); // Shows the original stringified version
    console.log(JSON.parse(data.toString().replace('\t','').replace('\r','').replace('\n',''))); // Trim the sequence "\r\n" off the end of the string
});

1
我也替换了\tconf = JSON.parse(confData.replace('\r','').replace('\n','').replace('\t','')); - Raeisi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接