What changed in jQuery 1.9 to cause a $.ajax call to fail with syntax error
Asked Answered
S

3

33

I'm making a REST DELETE call, which returns a 204. In jQuery 1.8.3 this works, and hits the request.done callback. But if I use 1.9 it goes to request.fail with a parsererror in the textStatus and a 'SyntaxError: Unexpected end of input' in the errorThrown.

remove = function (complete) {
            var self = this;
            var request = $.ajax({
              context: self,
              url: "/v1/item/" + itemId,
              dataType: "json",
              type: "DELETE"
            });
            request.done(removeCallback);
            request.fail(function (xhr, textStatus, errorThrown) {
                alert(errorThrown);
            });
            
        },

Anyone know what has changed in 1.9 that would cause this to fail, and what needs to change in order to fix it?

So, answering my own question it looks like this is in fact the problem:

From the jQuery upgrade guide

jQuery.ajax returning a JSON result of an empty string

Prior to 1.9, an ajax call that expected a return data type of JSON or JSONP would consider a return value of an empty string to be a success case, but return a null to the success handler or promise. As of 1.9, an empty string returned for JSON data is considered to be malformed JSON (because it is); this will now throw an error. Use the error handler to catch such cases.

So, if remove the dataType

dataType: "json",

It works in jQuery 1.8.3 and 1.9.

Shrink answered 22/1, 2013 at 21:53 Comment(2)
Well, it looks like it is this: jQuery.ajax returning a JSON result of an empty string Prior to 1.9, an ajax call that expected a return data type of JSON or JSONP would consider a return value of an empty string to be a success case, but return a null to the success handler or promise. As of 1.9, an empty string returned for JSON data is considered to be malformed JSON (because it is); this will now throw an error. Use the error handler to catch such cases.Shrink
Arg this has been driving me nuts, I spent forever trying to figure out why my test was no longer passing and why the 204 was giving an error.Sidewinder
S
21

An HTTP 204 response is not an empty string: it means there is no data. This is a valid response for delete and update operations.

This looks like a bug introduced in JQuery 1.9.

The reason removing the dataType property fixes this is because when it's set to "json" JQuery attempts to parse the content using JSON.parse and failing as a result. From the ticket:

This won't fail with any other dataType than "json" because the regression is due to the re-alignment of parseJSON with native JSON.parse (throwing an exception for null/undefined values).

Don't try the workaround suggested in the ticket of adding a handler for the 204 via the statusCode property, because both that handler and the error handler will be triggered. A possible solution is the following:

    $.ajax(url, {
    type: "DELETE",
    dataType: "json",
    error: function (error) {
        if (error.status === 204) {
            // Success stuff
        }
        else {
            // fail
        }
    }});
Sika answered 25/1, 2013 at 10:43 Comment(3)
I'll mark this as answered. Works though having success in your error response just seems wrong :). In my specific case, just removing the datatype 'json' worked but only because I wasn't actually sending any data... just hitting a url with an Id.Shrink
@GeneReddick this is just a suggested workaround until they fix it. Removing dataType 'json' would also work if you are sending a request payload, because this option actually refers to the response payload. The workaround above is useful if all your delete calls are going through a wrapper around "$.ajax".Sika
If the $.ajax call says the request will return JSON, then it should return JSON. An empty string isn't valid JSON, for example JSON.parse("") yields an error. If the response is empty then don't set the dataType; if the response is only there sometimes, use dataType: "text" and parse the JSON response when it is there.Linalool
O
9

I was having a very similar problem, and you helped my find my answer - so thank you. My solution, however is slightly different, so I figured I would share it.

As stated in the question, on the JQuery website it says:

Prior to 1.9, an ajax call that expected a return data type of JSON or JSONP would consider a return value of an empty string to be a success case, but return a null to the success handler or promise. As of 1.9, an empty string returned for JSON data is considered to be malformed JSON (because it is); this will now throw an error. Use the error handler to catch such cases.

I was passing JSON data to a method on my server with "void" as a return type because I did not need to do anything with returned data in the success function. You can no longer return null when passing JSON in an AJAX request in JQuery 1.9 +. This was possible in previous versions of JQuery however.

To stop getting an error and get the success function to fire instead, you must simply return valid JSON in your AJAX request. It doesn't matter what you pass, as long as it's valid, because (in my case anyways) you are not using the returned data.

Overlarge answered 14/2, 2013 at 20:14 Comment(1)
Thanks, this was exactly my problem as to why my success functions were not being called on my $.ajax calls.Paillasse
E
2

The problem seems to be that jQuery treats the empty body (where Content-Length is 0) of a 204 response as "". Which is one interpretation, but the downside is that "" gets treated like any other response string. So if you have called jQuery.ajax() with the dataType:json option, jQuery tries to convert "" to an object and throws an exception ("" is invalid JSON).

jQuery catches the exception and recovers, but if you prefer to avoid the exception altogether (in your development environment) you might do something like the following. Add in the "converters" option to jQuery.ajax() and use it to change "" responses to nulls (I do this when dataType is json). Something like :

var ajax_options =
    {
        /* ... other options here */
        "converters" :
            {
                "text json" :
                    function( result )
                    {
                        if ( result === "" ) result = null;
                        return jQuery.parseJSON( result );
                    }
            }
    };

var dfd = jQuery.ajax( ajax_options );
Expediency answered 22/2, 2014 at 22:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.