January 15, 2010
With the popularity of JavaScript JSON has become very very popular.
JSON which stands for JavaScript Object Notation
is a
popular way to send and receive data between browser and server.
jQuery makes it extremely easy to deal with JSON data. In the below example server sends a success message to browser. The JSON data looks like this.
{ 'success': 'record was successfully updated' }
The jQuery code to handle JSON data looks like this.
$.ajax({
type: "GET",
url: "test.js",
dataType: "json",
success: function (json) {
$("#result").text(json.success);
},
});
It all looks good and the code works with jQuery 1.3 .
However if you upgrade to jQuery 1.4 then above code will stop working. Why? jQuery 1.4 does strict JSON parsing using native parse method and any malformed JSON structure will be rejected.
jQuery 1.3 uses JavaScript’s eval to evaluate incoming JSON structure. Open firebug and type following example.
s = " { 'success' : 'record was updated' } ";
result = eval("(" + s + ")");
console.log(result);
You will get a valid output.
Note that all valid JSON structure is also valid JavaScript code so eval converts a valid JSON structure into a JavaScript object. However non JSON structure can also be converted into JavaScript object.
JSON specification says that all string values must use double quotes. Single quotes are not allowed. What it means is that following JSON structures are not valid JSON.
{ 'foo' : 'bar' }
{ foo: 'bar' }
{ foo: "bar" }
{ "foo" : 'bar' }
Even though above strings are not valid JSON if you eval them they will produce a valid JavaScript object. Since jQuery 1.3 uses eval on strings to convert JSON structure to JavaScript object all the above mentioned examples work.
However they will not work if you upgrade to jQuery 1.4 .
Using eval to convert JSON into JavaScript object has a few issue. First is the security. It is possible that eval could execute some malicious code. Secondly it is not as fast as native parse methods made available by browsers. However browsers adhere to JSON spec and they will not parse malformed JSON structures. Open firebug and try following code to see how native browser methods do not parse malformed JSON structure. Here is the link to the announcement of Firefox support for native JSON parsing . John Resig mentioned the need for jQuery to have native JSON parsing support here .
s = " { 'success' : 'record was updated' } ";
result = eval("(" + s + ")");
console.log(result); /* returns valid JavaScript object */
result2 = window.JSON.parse(s);
console.log(result2); /* throws error */
As you can see a string which was successfully parsed by eval
failed by
window.JSON.parse
. It might or might not fail in chrome. More on that later.
Since jQuery 1.4 will rely on browsers parsing the JSON structure malformed JSON
structures will fail.
In order to ensure that JSON is correctly parsed by the browsers, jQuery does some code cleanup to make sure that you are not trying to pass something malicious. You will not be able to test this thing directly using firebug but if you make an AJAX request and from server if you send response the you can verify the following code.
Following JSON structure will be correctly parsed in jQuery 1.3 . However the
same JSON structure will fail in jQuery 1.4 . Why? Because of dangling open
bracket [
.
' { "error" : "record was updated" }';
jQuery 1.4 has following code that does some data cleanup to get around the security issue with JSON parsing before sending that data to browser for parsing. Here is a snippet of the code.
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if (/^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
.replace(/(?:^|:|,)(?:\s*\[)+/g, "")))
Not all browsers parse JSON same way
Earlier I mentioned that following JSON structure will not be correctly parsed by browsers.
” { 'a':1 } ”
All browsers will fail to parse above JSON structure except chrome
. Look at
this blog titled Cross Browser JSON parsing to get
more insight into this issue.
If you have malformed JSON and you want to use jQuery 1.4 then you should send
the datatype as text
and then convert the returned JSON structure using eval.
Here is one way you can do that.
$.ajax({
url: "/url",
dataType: "text",
success: function (data) {
json = eval("(" + data + ")");
// do something with json
},
});
Ben Alman suggested another way in the comment section .
/* this should be the very first JavaScript inclusion file */
<script type=”text/javascript” language=”javascript”>window.JSON = null;</script>
jQuery attempts to parse JSON natively. However if native JSON parsing is not
available then it falls back to eval
. Here by setting window.JSON to null
browser is faking that it does not have support for native JSON parsing.
Here are the two commits which made most of the changes in the way parsing is done.
Use JSONLint if you want to play with various strings to see which one is valid JSON and which one is not.
If this blog was helpful, check out our full blog archive.