Skip to main content

Bug Tracker

Side navigation

#8417 closed bug (fixed)

Opened March 02, 2011 01:48AM UTC

Closed April 16, 2011 03:59PM UTC

Last modified August 16, 2013 01:01AM UTC

When posting AJAX and the data has "??" is formats it to jQuery<timestamp>?

Reported by: jason.jong@gmail.com Owned by: jaubourg
Priority: low Milestone: 1.6
Component: ajax Version: 1.5.1
Keywords: Cc:
Blocked by: Blocking:
Description

Works fine with 1.4.4

Example:

var myData = { AccountIds: 17, Message: "??" };

var encData = JSON.stringify(myData);

// all ok so far

$.ajax({

type: "POST",

url: "services/Messages.ashx?cmd=set",

data: jsonData,

dataType: "json",

success: function() {

}

});

// in the receiving end, then I read the stream, the message becomes

jQuery151044947751238942146_1299030184872?

Attachments (0)
Change History (47)

Changed March 02, 2011 02:15AM UTC by jason.jong@gmail.com comment:1

i tried to replicate the issue on jsfiddle, but dont know how to see the data posted back

http://jsfiddle.net/aVddJ/3/

Changed March 02, 2011 06:45AM UTC by jaubourg comment:2

resolution: → wontfix
status: newclosed

Default encoding in ajaxSettings is x-www-form-urlencoded. So you have to encode your data using encodeURIComponent().

See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURIComponent

Changed March 16, 2011 10:14AM UTC by shiki comment:3

The weird thing about this is if I set the ajax settings to:

contentType: "application/json; charset=utf-8",

dataType: "json",

processData: false,

The "??" string in data still gets replaced with something like "jQuery151020082441558501163_1300269082410". If I'll remove "dataType: json" though, it works.

Sample: http://jsfiddle.net/5gwEF/

(I used Firebug to see what the ajax sending). This seems to work with 1.4.4.

I'm curious on what's really the correct way to send a JSON string with $.ajax. Encoding with encodeURIComponent() would turn "??" into "%20%3F%3F". That's what the server's gonna receive. Is the server responsible for decoding it (e.g. urldecode) even if the sent content type is "application/json"?

Interestingly, that code in jsFiddle is pretty much how Backbone uses it to send JSON to the server. Direct link here: http://documentcloud.github.com/backbone/docs/backbone.html#section-111

Changed March 29, 2011 11:43PM UTC by jaubourg comment:4

#8697 is a duplicate of this ticket.

Changed March 30, 2011 12:05AM UTC by anonymous comment:5

So will this be fixed?

Is the solution to encodeURIComponent() all the inputs and then URLDecode on the server?

Changed March 31, 2011 07:27PM UTC by anonymous comment:6

Any update on this ticket? I keep running into this issue and not sure how to work around it.

Should we call encodeURIComponent() on the json string or will this be fixed in jquery?

Thanks.

Changed March 31, 2011 08:29PM UTC by Jason Davies comment:7

This is happening for me too. As mentioned in the 3rd comment, the workaround is to remove dataType: "json". I'm not sure why this replacement is occurring here, I'm guessing this is related to JSONP.

I suggest reopening - it doesn't seem to be related to using encodeURIComponent as that would only apply for a content type of x-www-form-urlencoded. This can be reproduced for a content type of application/json.

Changed March 31, 2011 09:02PM UTC by cowboy comment:8

Guys, the data that $.ajax expects is either a query string, like a=1&b=2 or an object (that $.ajax serializes into a query string internally, using $.param) like {a: 1, b: 2}.

By passing a JSON string in as form data, you're effectively requesting a URL like:

process.php?{"a":1,"b":2}

which makes no sense. Note that both GET and POST work in a similar enough way for the purpose of this comment that you shouldn't worry about the semantics. Either way, the server is really expecting a URL like:

process.php?a=1&b=2

The solution: just pass the object in as data, without first stringifying it to JSON, and you should be all set. See this example.

Changed March 31, 2011 09:22PM UTC by ajpiano comment:9

OR if you actually WANT to pass a JSON string to the server, for whatever reason, you have to pass it as one of the values in the data parameter

$.ajax({
 data: {
  foo: JSON.stringify(bar);
 }
});

Changed March 31, 2011 09:27PM UTC by danheberden comment:10

Changed March 31, 2011 10:32PM UTC by Jason Davies comment:11

Hi all, thanks for taking a look. I'm not too familiar with jsFiddle but I managed to reproduce the problem in this one: http://jsfiddle.net/zs4Ez/5/

Note that you have to use the "Resources" tab in Webkit to view the request payload that's being sent to the server to see the problem. Note that I am using JSON.stringify() for the data.

Changed March 31, 2011 10:47PM UTC by timmywil comment:12

Replying to [comment:11 Jason Davies]:

Yes, as the previous commenters explained, your data is not valid. You can do one of the other two options.

Changed March 31, 2011 11:23PM UTC by Jason Davies comment:13

Replying to [comment:12 timmywil]:

Hi Timmy, thanks for looking at this.

The data itself is not valid, perhaps it'll help if I explain the use case. I'm simply trying to POST a string (containing JSON data) as the request body. This is common for REST APIs that take JSON data as input via the POST body.

It seems the default setup is to replace all instances of ?? in the POST body with a callback, even for normal dataType="json" requests. Or perhaps I'm misunderstanding the point of the dataType parameter? From the docs: "The type of data that you're expecting back from the server." - doesn't seem relevant.

The thing is, my request is *not* a JSONP request, so I don't know why this ?? replacement is occurring at all.

Changed March 31, 2011 11:28PM UTC by Jason Davies comment:14

I know I can turn this behaviour off by setting jsonp: false, but it seems odd that JSONP replacement occurs by default even when JSONP is not being used.

Changed March 31, 2011 11:33PM UTC by timmywil comment:15

Of course. REST! However, you can ensure that requests are not converted to jsonp and override the addition of a callback by setting jsonp to false. Click the post in firebug lite and go the POST tab to view the data. http://jsfiddle.net/timmywil/zs4Ez/6/

It should be more restful. ;)

Changed March 31, 2011 11:35PM UTC by timmywil comment:16

Well, it seems you figured that out. The automatic conversion to jsonp exists so that the getJSON function (which is really just a shortcut for ajax as you know) can also be used for jsonp.

Changed March 31, 2011 11:53PM UTC by Jason Davies comment:17

See https://github.com/jquery/jquery/pull/294 for my fix, which only affects requests with data in the request body, so won't affect getJSON.

Changed March 31, 2011 11:55PM UTC by ajpiano comment:18

resolution: wontfix
status: closedreopened

Changed March 31, 2011 11:55PM UTC by ajpiano comment:19

component: unfiledajax
priority: undecidedlow

Changed April 01, 2011 12:28AM UTC by jaubourg comment:20

owner: → jaubourg
status: reopenedassigned

Replying to [comment:17 Jason Davies]:

See https://github.com/jquery/jquery/pull/294 for my fix, which only affects requests with data in the request body, so won't affect getJSON.

I commented on this request and closed it.

shiki exhibited the actual bug in comment 3 ( http://bugs.jquery.com/ticket/8417#comment:3 ): if contentType is x-www-form-urlencoded then you have to use encodeURIComponent when providing data as a string:

$.ajax({
 data: encodeURIComponent( JSON.stringify(bar) )
});

In that case, the regexp is never positive and, since the encoding is provided in the request headers, the server will decode the data string properly.

Now, when contentType does not involve url encoding, then, yes, here you have an actual bug since the prefilter shouldn't attempt to regexp test the data.

jQuery 1.4.4 was far too lenient regarding encoding. If contentType is x-www-form-urlencoded, you have to url-encode your data, or else, ajax is perfectly entitled to interpret special characters as it sees fit. Once again: encoding is NOT optional.

Didn't see the conversation was still going and missed shiki's comment which, again, was right on while acknowledging the need for encoding when specified. I'm taking ownership.

Changed April 01, 2011 09:52AM UTC by Jason Davies comment:21

I've updated the pull request with a fix that checks for the contentType instead: https://github.com/jquery/jquery/pull/294

Changed April 07, 2011 11:01AM UTC by ajpiano comment:22

#8798 is a duplicate of this ticket.

Changed April 16, 2011 03:57PM UTC by jaubourg comment:23

#8895 is a duplicate of this ticket.

Changed April 16, 2011 03:59PM UTC by jaubourg comment:24

resolution: → fixed
status: assignedclosed

https://github.com/jquery/jquery/commit/4ad9b44deada9da9639f53b1ca3cc4cf2ebf2df2

Use proper encoding or set it properly using contentType.

Changed April 16, 2011 04:00PM UTC by jaubourg comment:25

milestone: 1.next1.6

Changed April 30, 2011 05:50PM UTC by rwaldron comment:26

#9032 is a duplicate of this ticket.

Changed May 19, 2011 01:03AM UTC by rwaldron comment:27

#9340 is a duplicate of this ticket.

Changed May 26, 2011 03:12PM UTC by jaubourg comment:28

#9430 is a duplicate of this ticket.

Changed June 15, 2011 03:58AM UTC by dgrobler comment:29

Still getting the same issue with 1.6.1 - explicitly specifying contentType as "application/json; charset=utf-8".

Sending data to REST endpoint (Microsoft Dynamics CRM 2011 oData REST endpoint to be exact)

Changed June 15, 2011 05:31AM UTC by jaubourg comment:30

Replying to [comment:29 dgrobler]:

Still getting the same issue with 1.6.1 - explicitly specifying contentType as "application/json; charset=utf-8". Sending data to REST endpoint (Microsoft Dynamics CRM 2011 oData REST endpoint to be exact)

Could you make a fiddle demonstrating the issue?

Changed June 16, 2011 02:41AM UTC by dgrobler comment:31

Replying to [comment:30 jaubourg]:

Replying to [comment:29 dgrobler]: > Still getting the same issue with 1.6.1 - explicitly specifying contentType as "application/json; charset=utf-8". > > Sending data to REST endpoint (Microsoft Dynamics CRM 2011 oData REST endpoint to be exact) Could you make a fiddle demonstrating the issue?

Tricky putting a working fiddle together (need to be able to authenticate against a Microsoft Dynamics CRM 2011 oData REST endpoint) What I can do is post the following that might help:

jQuery AJAX Code

    $.ajax(
    {
        type: "POST",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName,
        data: jsonEntity,
        beforeSend: function (XMLHttpRequest) {
            //Specifying this header ensures that the results will be returned as JSON.             
            XMLHttpRequest.setRequestHeader("Accept", "application/json; charset=utf-8");
        },
        success: function (data, textStatus, XmlHttpRequest) {
            if (successCallback) {
                successCallback(data.d, textStatus, XmlHttpRequest);
            }
        },
        error: function (XmlHttpRequest, textStatus, errorThrown) {
            if (errorCallback)
                errorCallback(XmlHttpRequest, textStatus, errorThrown);
            else
                CaseErrorHandler(XmlHttpRequest, textStatus, errorThrown);
        }
    });

JSON that is passed into the data parameter:

"{"CustomerId":{"Id":"{6E89243F-111D-E011-872A-00505682001B}","Name":"Interglobal","LogicalName":"account"},"Title":"John Bain","new_UserStory":null,"CaseTypeCode":{"Value":2},"new_CaseStatus":{"Value":100000000},"new_StartTime":null,"new_EndTime":null,"new_ClientId":{"Id":"{6E89243F-111D-E011-872A-00505682001B}","Name":"Interglobal","LogicalName":"account"},"new_CustomerPolicyId":{"Id":"{ECE85351-8D7B-E011-8686-00505682001B}","Name":"John Bain - ABC123","LogicalName":"new_customerpolicy"},"new_City":null,"new_Country":null,"new_CustomerId":{"Id":"{A913AB1A-3196-E011-8D9F-00505682001B}","Name":"John Lawrie Bain","LogicalName":"contact"},"new_Handover":true,"new_HandoverReasonDetails":"Test jquery 1.6.1 with lots of question marks","new_HandoverScript":"Test jquery 1.6.1 with lots of question marks??","new_HandoverToId":{"Id":"{24CE0524-BC34-E011-872A-00505682001B}","Name":"Dieter Grobler","LogicalName":"systemuser"},"new_HandoverReason":{"Value":100000000},"new_voicemailsent":false,"new_Whiteboard":true,"new_WhiteboardReasonDetails":"Test jquery 1.6.1 with lots of question marks","new_WhiteboardReason":{"Value":100000000},"new_FinancialCaseStrategy":null,"new_FinancialCaseStrategyUpdated":null,"new_LogisticalCaseStrategy":null,"new_LogisticalCaseStrategyUpdated":null,"new_MedicalCaseStrategy":null,"new_MedicalCaseStrategyUpdated":null,"TransactionCurrencyId":{"Id":"{4E87F4A0-041D-E011-B306-00505682001B}","Name":"New Zealand Dollar","LogicalName":"transactioncurrency"},"new_ReserveAmount":{"Value":"5000"},"new_RequireEvacuationRepatriation":false}"

Request JSON:

{"CustomerId":{"Id":"{6E89243F-111D-E011-872A-00505682001B}","Name":"Interglobal","LogicalName":"account"},"Title":"John Bain","new_UserStory":null,"CaseTypeCode":{"Value":2},"new_CaseStatus":{"Value":100000000},"new_StartTime":null,"new_EndTime":null,"new_ClientId":{"Id":"{6E89243F-111D-E011-872A-00505682001B}","Name":"Interglobal","LogicalName":"account"},"new_CustomerPolicyId":{"Id":"{ECE85351-8D7B-E011-8686-00505682001B}","Name":"John Bain - ABC123","LogicalName":"new_customerpolicy"},"new_City":null,"new_Country":null,"new_CustomerId":{"Id":"{A913AB1A-3196-E011-8D9F-00505682001B}","Name":"John Lawrie Bain","LogicalName":"contact"},"new_Handover":true,"new_HandoverReasonDetails":"Test jquery 1.6.1 with lots of question marks","new_HandoverScript":"Test jquery 1.6.1 with lots of question marksjQuery15102242055933082286_1308190892929","new_HandoverToId":{"Id":"{24CE0524-BC34-E011-872A-00505682001B}","Name":"Dieter Grobler","LogicalName":"systemuser"},"new_HandoverReason":{"Value":100000000},"new_voicemailsent":false,"new_Whiteboard":true,"new_WhiteboardReasonDetails":"Test jquery 1.6.1 with lots of question marks","new_WhiteboardReason":{"Value":100000000},"new_FinancialCaseStrategy":null,"new_FinancialCaseStrategyUpdated":null,"new_LogisticalCaseStrategy":null,"new_LogisticalCaseStrategyUpdated":null,"new_MedicalCaseStrategy":null,"new_MedicalCaseStrategyUpdated":null,"TransactionCurrencyId":{"Id":"{4E87F4A0-041D-E011-B306-00505682001B}","Name":"New Zealand Dollar","LogicalName":"transactioncurrency"},"new_ReserveAmount":{"Value":"5000"},"new_RequireEvacuationRepatriation":false}

Note that my question marks (??) are replaced by jQuery15102242055933082286_1308190892929 in my request. The server does respond as expected with the correct result but the jQuery call triggers the error event handler rather than success.

Hope that helps and I hope that it is not my stupid mistake!

Changed August 24, 2012 08:16AM UTC by anonymous comment:32

I'm using jQuery 1.8 and the problem is still there.

Using '??' makes jQuery replace that with the string generated by:

jQuery.ajaxSetup({

jsonp: "callback",

jsonpCallback: function() {

return jQuery.expando + "_" + ( jsc++ );

}

});

Changed October 04, 2012 08:30PM UTC by swdc17@gmail.com comment:33

Please re-open this ticket, the problem still exists.

Changed October 10, 2012 01:59PM UTC by anonymous comment:34

Replying to [comment:33 swdc17@…]:

Please re-open this ticket, the problem still exists.

Changed October 16, 2012 09:47AM UTC by alec comment:35

Still not fixed in 1.8.2.

Changed October 16, 2012 10:01AM UTC by alec comment:36

Forget about my comment. Setting contentType to "application/json; charset=utf-8" fixes the issue.

Changed December 06, 2012 11:35AM UTC by erlend@oftedal.no comment:37

Compare these two:

http://jsfiddle.net/FyRBK/3/

http://jsfiddle.net/FyRBK/4/

Setting the content type in different ways, gives different results.

This is still a bug, and should be reopened.

Changed December 06, 2012 12:22PM UTC by jaubourg comment:38

_comment0: Replying to [comment:37 erlend@…]: \ > Compare these two: \ > http://jsfiddle.net/FyRBK/3/ \ > http://jsfiddle.net/FyRBK/4/ \ > \ > Setting the content type in different ways, gives different results. \ > \ > This is still a bug, and should be reopened. \ \ No, the first method sets the content type of the *request* body, the second, the content type of the *response* body. There is no bug here.1354797324791727

Replying to [comment:37 erlend@…]:

Compare these two: http://jsfiddle.net/FyRBK/3/ http://jsfiddle.net/FyRBK/4/ Setting the content type in different ways, gives different results. This is still a bug, and should be reopened.

Scrap the previous comment. I wasn't quite awake.

So, jQuery doesn't inspect headers sent the second way because some transports won't use them. Use contentType to set the encoding of your data. It's not a bug.

Changed January 02, 2013 02:10PM UTC by erlend@oftedal.no comment:39

replying to jaubourg

I humbly disagree. It is a bug. Why is changing the _body_ sent in a _POST_ something jQuery should do? When is this useful?

The principle of least surprise.

Changed March 13, 2013 08:51PM UTC by jo.jcat@gmail.com comment:40

We recently ran into an issue not unlike this one. The type was explicitly set to POST, but was silently converted to GET inside the inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); I understand the body conversion when setting the type to JSONP, but if the type is still JSON (set explicitly) and the method is POST (set explicitly), the conversion from POST to GET should not happen in the presence of a double question mark.

Changed March 14, 2013 06:39PM UTC by anonymous comment:41

Seems to come down to "Handle cache's special case and global." prefilterOrFactory() is doing the actual swap if s.crossDomain is set. I can't find the location where prefilterOrFactory is defined or the conditions under which it is added to the handler.

One thing remains clear: jQuery.ajaxPrefilter (and, subsequently, a conversion from POST to GET) ONLY invoked if there's a double '??' in the data string.

Changed April 10, 2013 11:08PM UTC by jaubourg comment:42

#13766 is a duplicate of this ticket.

Changed May 27, 2013 04:21PM UTC by jaubourg comment:43

#13913 is a duplicate of this ticket.

Changed May 27, 2013 08:45PM UTC by anonymous comment:44

So what is the solution for this bug ?

Changed July 30, 2013 10:25AM UTC by anonymous comment:45

Replying to [comment:44 anonymous]:

So what is the solution for this bug ?

Maybe old information. But alec's solution works fine for me. I.e. setting contentType to "application/json; charset=utf-8"

Changed July 31, 2013 05:43AM UTC by anonymous comment:46

Still happening in 1.8.3

Changed August 16, 2013 01:01AM UTC by sean.baker@bb-technologies.com comment:47

I just ran into this issue as well - using jQuery 1.8.2

I added jsonp: false as suggested by Jason Davies above for now as a work-around.

I am posting a JSON string as data, using settings processData: false and dataType: 'json'. This has worked for a long time for me, but I just discovered it fails if any field ever has a double quotation mark in it as noted by others above.