#13654 closed bug (notabug)
Ajax response with status code 204 triggers fail() on cross-domain requests
Reported by: | ojak | Owned by: | ojak |
---|---|---|---|
Priority: | undecided | Milestone: | None |
Component: | unfiled | Version: | 1.9.1 |
Keywords: | Cc: | jaubourg | |
Blocked by: | Blocking: |
Description
Ajax response with status code 204 triggers fail() on cross-domain requests. Example
http://localhost:8080/served_page.html >> .ajax() to localhost:8080 with response 204 triggers .done() >> .ajax() to localhost:8081 with response 204 triggers .fail() with xhr.status = 0
Change History (15)
comment:1 Changed 10 years ago by
comment:2 Changed 10 years ago by
One note, the ajax request works when 'script' is specified as the dataType, but fails on 'text'. Since 204 is a success with No Content, a 204 response should always trigger a success unless there is any content, which would be an invalid 204.
I think the most correct way to handle this would probably be to define an expected dataType return of 'none' or 'empty'. Any thoughts?
comment:4 Changed 10 years ago by
I'm ready to look into this, with a proper test case ;)
Off the top of my head, if it's cross-domain, using script tag injection, then we don't get the status code anyway, so we just cannot handle it appropriately.
I'm really confused about the dataType juggling described but I cannot draw any conclusion out of vague descriptions: test cases are mandatory especially for ajax bugs.
Also, which browser ? What is the error triggered (the args given to the error callbacks) ? etc etc
comment:5 Changed 10 years ago by
Owner: | set to ojak |
---|---|
Status: | new → pending |
We're awaiting a test case from the reporter then; @ojak please provide more information as requested above.
comment:6 Changed 10 years ago by
Status: | pending → new |
---|
Here's some example code with 4 tests, the resulting firebug console logs, and sample nginx.conf to setup 204's on localhost:
https://gist.github.com/ojak/5241273
I tested on Firefox 19 and Chrome 25.0.1364.172 (although Chrome needs to be run with flags to avoid Access-Control-Allow-Origin issues).
comment:7 Changed 10 years ago by
All right:
- for dataType "script", a script tag is used as a transport, so jQuery cannot access the actual status code, so it assumes 200 for success, 404 for error. There is no way around it. It is working as expected. If you wanna avoid the script transport, force crossDomain to false.
- for dataType "text", could you log the actual arguments in the fail callback ? Logging "Fail" doesn't give much information as to why the request actually fails.
Thanks for the follow up btw. If you can log the arguments given to the fail handler in TEST4, I may be able to assess what's going on without having to setup the env you've already setup yourself.
comment:8 Changed 10 years ago by
Status: | new → pending |
---|
comment:9 Changed 10 years ago by
Status: | pending → new |
---|
I updated the gist on the fail with some xhr response information:
https://gist.github.com/ojak/5241273
--- TEST4: Test different port with 'text' dataType GET http://localhost:8082/204 204 No Content Fail - xhr.status : 0 - xhr.statusText : error - xhr.response : undefined - xhr.responseText : - xhr.responseXML : undefined - textStatus : error - errorThrown : === FAIL AND INCORRECT STATUSCODE
comment:10 Changed 10 years ago by
Status: | new → pending |
---|
Hmmm, looks a lot like a network error (status code 0, no errorThrown). At least we know it's not the conversion logic going wrong.
Just out of curiosity, and before I dive deeper in there, does the request work using pure xhr?
Something along the lines of the following snippet (untested):
var xhr = $.ajaxSettings.xhr(); xhr.open( "GET", "http://localhost:8082/204" ); xhr.onsuccess = function() { console.log( "success", xhr, arguments ); }; xhr.onerror = function() { console.log( "error", xhr, arguments ); }; xhr.onabort = function() { console.log( "abort", xhr, arguments ); }; xhr.ontimeout = function() { console.log( "abort", xhr, arguments ); }; xhr.send();
Also, you should test with http://code.jquery.com/jquery-git.js so that you use jQuery latest (not that it should matter much but you never know).
comment:11 Changed 10 years ago by
Status: | pending → new |
---|
Interesting. Tried that out and here are the results:
Screenshot of firebug results: http://s3.amazonaws.com/ojak/screenshot-jquery-xhr.png
Code to reproduce: https://gist.github.com/ojak/5247073
Same results against the current jQuery dist built from the master branch.
comment:12 Changed 10 years ago by
My guess is you have a Content-Type
in your response headers that trigger the xml parsing logic in FF. Same in Chrome?
Sounds less and less like a jQuery bug...
comment:13 Changed 10 years ago by
The attached screenshot shows the Response Header, which show that the response headers do not have a Content-Type:
http://s3.amazonaws.com/ojak/screenshot-xhr-response-headers.png
I still think it's a jQuery bug since 204s should not return a "Content-Type" from the server, since by definition there should be no content:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
But in the end, both Chrome and Firefox are seeing failures, so maybe that's the problem? There should probably be a dataType of "none" defined in jQuery, since the response is not failing.
comment:14 Changed 10 years ago by
Resolution: | → notabug |
---|---|
Status: | new → closed |
I think you should take this discussion into the forums or stackoverflow.
From what you showed, the response is not successful. The error handler is triggered on the native XHR. The native XHR is not part of jQuery just replace $.ajaxSettings.xhr()
by new XMLHttpRequest()
to convince yourself no jQuery code is used here.
What this means is that browsers seem to have a problem with your 204 responses. From what I gather from the error message in firebug, it seems as if Firefox is trying to parse the response as XML (not jQuery but Firefox itself), hence why I made the wild guess you had a Content-Type response header (a header that is provided by the server, not something jQuery would incante out of thin air). It doesn't seem to be the problem though. Maybe your 204 response has a body (I see an XML tab in http://s3.amazonaws.com/ojak/screenshot-xhr-response-headers.png which doesn't seem right at all), again something that is provided by the server not client-side code.
I dunno if it's a configuration problem server-side, a bug in the browsers, a problem specific to CORS or some convoluted behaviour that makes no sense but is actually standard. What's clear though is that jQuery is not responsible for the problem and no action on our part is needed nor possible: if the native XHR notifies an error with the wrong status code, jQuery just cannot "guess" what the original status code was.
I'll close this as notabug but, please, feel free to add a link to any forum or stackoverflow discussion/question related to the issue.
comment:15 Changed 10 years ago by
Gotcha, thanks.
Just for a little extra color on the issue, there appears to be a 3+ year old bug in Firefox for this behavior:
https://bugzilla.mozilla.org/show_bug.cgi?id=521301
Anyhow, thanks so much for helping track down these issues. I think the best advice going forward for others coming across this issue is: "don't use 204's for AJAX requests, use 200's with empty content"... which is a bummer.
Might be worth updating the jQuery docs to mention this behavior as a warning?
A fix was attempted in ticket:13261 that seems to have only solved same domain requests.