#8417 closed bug (fixed)
When posting AJAX and the data has "??" is formats it to jQuery<timestamp>?
Reported by: | 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?
Change History (47)
comment:1 Changed 12 years ago by
comment:2 Changed 12 years ago by
Resolution: | → wontfix |
---|---|
Status: | new → closed |
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
comment:3 Changed 12 years ago by
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
comment:5 Changed 12 years ago by
So will this be fixed?
Is the solution to encodeURIComponent() all the inputs and then URLDecode on the server?
comment:6 Changed 12 years ago by
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.
comment:7 Changed 12 years ago by
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.
comment:8 Changed 12 years ago by
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.
comment:9 Changed 12 years ago by
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); } });
comment:10 Changed 12 years ago by
comment:11 follow-up: 12 Changed 12 years ago by
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.
comment:12 follow-up: 13 Changed 12 years ago by
Replying to Jason Davies:
Yes, as the previous commenters explained, your data is not valid. You can do one of the other two options.
comment:13 Changed 12 years ago by
Replying to 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.
comment:14 Changed 12 years ago by
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.
comment:15 Changed 12 years ago by
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. ;)
comment:16 Changed 12 years ago by
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.
comment:17 follow-up: 20 Changed 12 years ago by
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.
comment:18 Changed 12 years ago by
Resolution: | wontfix |
---|---|
Status: | closed → reopened |
comment:19 Changed 12 years ago by
Component: | unfiled → ajax |
---|---|
Priority: | undecided → low |
comment:20 Changed 12 years ago by
Owner: | set to jaubourg |
---|---|
Status: | reopened → assigned |
Replying to 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.
comment:21 Changed 12 years ago by
I've updated the pull request with a fix that checks for the contentType instead: https://github.com/jquery/jquery/pull/294
comment:24 Changed 12 years ago by
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
https://github.com/jquery/jquery/commit/4ad9b44deada9da9639f53b1ca3cc4cf2ebf2df2
Use proper encoding or set it properly using contentType.
comment:25 Changed 12 years ago by
Milestone: | 1.next → 1.6 |
---|
comment:29 follow-up: 30 Changed 12 years ago by
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)
comment:30 follow-up: 31 Changed 12 years ago by
Replying to 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?
comment:31 Changed 12 years ago by
Replying to jaubourg:
Replying to 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!
comment:32 Changed 11 years ago by
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++ );
}
});
comment:33 follow-up: 34 Changed 11 years ago by
Please re-open this ticket, the problem still exists.
comment:34 Changed 11 years ago by
Replying to swdc17@…:
Please re-open this ticket, the problem still exists.
comment:36 Changed 11 years ago by
Forget about my comment. Setting contentType to "application/json; charset=utf-8" fixes the issue.
comment:37 follow-up: 38 Changed 11 years ago by
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.
comment:38 Changed 11 years ago by
Replying to 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.
comment:39 Changed 10 years ago by
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.
comment:40 Changed 10 years ago by
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.
comment:41 Changed 10 years ago by
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.
comment:45 Changed 10 years ago by
Replying to 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"
comment:47 Changed 10 years ago by
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.
i tried to replicate the issue on jsfiddle, but dont know how to see the data posted back
http://jsfiddle.net/aVddJ/3/