8

I'm retrieving some stringifyed JSON via TCP in node.js an want to parse it. So my approach is similiar to this. I shortend and simplified it, so you don't have to know the surrounding logic.

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

The complete (beautified) JSON is this. As you can see, there are no errors.

{
    "result": "success",
    "source": "chat",
    "success": {
        "message": "test",
        "time": 1331770513,
        "player": "silvinci"
    }
}

But JSON.parse(data.toString()) always throws me this dumb error:

{"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)

So I thougt: "What could be wrong with the JSON-String. Let's try it directly. Should not work." Surprise, Surprise! It worked. Why does it work when I directly enter the String?

8
  • 2
    Did you actually run the shortened and simplified code? Commented Mar 15, 2012 at 1:40
  • 1
    Maybe the stream contains some weird control characters... is data a string or already the parsed object (or something else)? Commented Mar 15, 2012 at 1:40
  • 1
    @FelixKling has a good point. What is data.toString().charCodeAt(0)? Commented Mar 15, 2012 at 1:41
  • You are right, and I'm dumb. There is one line break hidden inside the JSON, that wasn't encoded the right way. Commented Mar 15, 2012 at 1:46
  • @silvinci, ah. Regular CR LF are okay (RFC 4627 2.), but it might have been something like a BOM. Commented Mar 15, 2012 at 1:54

3 Answers 3

18

Thanks to @Felix Kling I found my bug. It's very important to filter unescaped characters, especially outside the stringified JSON. I didn't and overlooked an invisible linebreak right after the stringified JSON.

This is the fix:

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
});

Please note, that this only works for me, as I have a very specialized case. The server is always responding in lines of JSON, that are terminated with an \r\n - not the whitespace characters, but literally backslash r and backslash n.
Your code may (or probably) fail due to other errors. But checking the server's response is a good starting point when you get parsing errors.

As @Zack correctly pointed out, this is a more general fix for removing unintended whitespace:

JSON.parse(data.toString().trim());
Sign up to request clarification or add additional context in comments.

4 Comments

Not knowing the context, it seems a little dangerous to unconditionally truncate the string. Maybe you should add a test for the offending characters before slicing.
In my case every response is terminated with \r\n. But you're right in general, so I appended a notice.
If you're seeing this issue and would like a more general solution use something like: JSON.parse(data.toString().trim()); String.prototype.trim will remove leading and trailing whitespace.
@Zack yep! Added it to the answer. :)
4

I had a similar issue. For a more general solution, this will work too. It takes off all whitespace before and after the string so you don't have to do the specific substring length.

JSON.parse(data.trim());

Comments

1

Instead of blindly removing last 4 chars, I suggest to remove the offending chars only:

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 Comment

I've replaced \t too. conf = JSON.parse(confData.replace('\r','').replace('\n','').replace('\t',''));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.