I have the following code:
function callXhr(method, url, data, expectedStatus, expectedStatusText, callback) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.setRequestHeader("Authorization", make_base_auth("Admin", "Admin"));
//Setup callback
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 ) {
if (expectedStatus !== undefined && expectedStatusText !== undefined && expectedStatus !== null && expectedStatusText !== null) {
equal(xhr.status.toString() + ' : ' + xhr.statusText, expectedStatus.toString() + ' : ' + expectedStatusText, method + ': ' + url + ' (status)');
}
callback(xhr);
}
};
try {
xhr.send(data);
} catch (ex) {
ok(false, ex.toString());
start();
}
ok(true, "The test framework should cause this test to pass");
}
asyncTest('XMLHttpRequest test', function () {
callXhr('GET', '/UnitTest/ValidateErrorCode', null, 400, 'Bad Request', function () { start(); });
});
This passes in every browser except PhatomJS. In PhantomJS xhr.status value is 0. This happens only when server returns error codes, like 400, 404, etc. Valid results, like 200, work fine. I need to be able to differentiate between error codes.
So, I separated the code from QUnit. It seems that XMLHttpRequest when issued synchronisly, works okay. When async, status and statustext are 0 and blank. Here are examples to try:
function make_base_auth(user, password) {
var tok = user + ':' + password;
var hash = btoa(tok);
return "Basic " + hash;
}
function log(text) {
document.write(text);
}
//log("loaded<br>");
//var xhr = new XMLHttpRequest();
//var url = "/UnitTest/ValidateErrorCode";
//log("loading: " + url + "<br>");
//try {
// xhr.open("GET", url, false);
// xhr.setRequestHeader("Authorization", make_base_auth("Admin", "Admin"));
// xhr.send(null);
// log("xhr.status: " + xhr.status.toString());
//}
//catch (ex)
//{
// log("err: " + ex);
//}
var xhr = new XMLHttpRequest();
var url = "/UnitTest/ValidateErrorCode";
xhr.open("GET", url, true);
xhr.setRequestHeader("Authorization", make_base_auth("Admin", "Admin"));
//Setup callback
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
log("Status: " + xhr.status.toString() + "<br>");
}
};
try {
log("loading: " + url + "<br>");
xhr.send(null);
log("No issue sending data.<br>");
} catch (ex) {
log("error: " + ex.toString() + "<br>");
}
Any chance you've tried using handlers for the more modern load, error, etc. events for the XHR? The onreadystatechange handler is really only included for historical purposes (i.e. oldIE) so it could very well be buggy.
See here for an example: https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress
James, just tried it.
var xhr = new XMLHttpRequest();
var url = "/UnitTest/ValidateErrorCode";
xhr.open("GET", url, true);
xhr.setRequestHeader("Authorization", make_base_auth("Admin", "Admin"));
//Setup callback
//xhr.onreadystatechange = function () {
// if (xhr.readyState === 4) {
// log("Status: " + xhr.status.toString() + "<br>");
// }
//};
xhr.addEventListener("load", function () {
log("load Status: " + xhr.status.toString() + "<br>");
}, false);
xhr.addEventListener("error", function () {
log("error Status: " + xhr.status.toString() + "<br>");
}, false);
try {
log("loading: " + url + "<br>");
xhr.send(null);
log("No issue sending data.<br>");
} catch (ex) {
log("error: " + ex.toString() + "<br>");
}
It works in IE, Chrome, etc... load event fires and I get status code of 400, which is what the call returns.
In phantomjs error event fires, but the status code is 0.
Ilya
Edit: Looking at previous comments I feel I should add I'm running phantomjs 1.9.0, Windows 8 64bit.
Dears,
I had the same issue with a slightly different config. Instead of using XHR directely, I'm using jQuery.ajax() in sync mode.
My program works fine under Chrome. However, when it is being tested using PhantomJS, the jqXHR.status is set to 0 for none-existing resources. To get 404 instead, I have added '--web-security=no' to the command line starting the test.
For more details, see 'http://stackoverflow.com/questions/15913170/phantom-js-synchronous-ajax-request-network-err-xmlhttprequest-exception-101'
Warm regards.
I'm facing this same issue with the jquery-ujs test suite with PhantomJS 1.9.2 and QUnit 1.12.0 - I tried to turn off the --web-security flag but the failed xhr gets mangled somewhere. Here is my failing test case. There is any alternative for fixing this behavior? Let me know if I can do something else to help fixing it.
We worked around this by using http://www.awesomium.com/
+1, seeing this when running mocha tests as well. Seems any error status codes (400's, 500's) return a status of 0.
This is still an issue.
Almost 2 years old now?
The problem seems to occur only when a local .js file makes a request to a server. It still happens, even with --web-security turned off. Any workarounds as for now (apart from ignoring these tests in phantom)? There seem to be no info whatsoever of the status code (or anything else, for that matters) in the whole jquery's error object...
Just to make it very clear. This problem has nothing to do with JQuery. It has everything to do with Phantom's implementation of XHR. I don't use JQuery and I too have this problem. Let's try and avoid to introduce variables into this problem that are completely unrelated.
I just ran into this as well - using Grunt to call Jasmine. What's odd is, my code is calling an API multiple times and it only fails for some of them. Running the Jasmine UT outside of Grunt and Phantom and it works fine. (The remote server uses CORS.)
I am running into this issue as well. It comes down to phantomjs XHR request having a request.status equal to 0 when it should be a 200. XHR is a critical component, so I am unpleasantly surprised to see this issue open for this long.
@ariya are there any plans to fix this? Is it fixed in a different branch/release?
I'm also experiencing this issue using AngularJS' $http module. The error callback is properly called, but result.status is equal to 0 instead of the expected 409.
+1 seeing intermittent failed XHR requests when a local file attempts to POST to a remote server.
I was able to resolve this for my particular use case by overriding all XHR POST requests to execute synchronously.
var openOriginal = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
if(arguments[0] === "POST") {
arguments[2] = false;
}
return openOriginal.apply(this, arguments);
};
var script = document.createElement("script");
script.src = "file:///your-local-file.js";
script.type = "application/javascript";
script.async = false;
document.getElementsByTagName("head")[0].appendChild(script);
Synchronous XHR is a bug, not a feature, and should never have been part of the spec imho. In other words, cute workaround, but rather useless in the real world.
It also brakes all Dojo tests.
Sync requests was working in phantomjs v1.9.7 and now it returns 0 in v2.0
dojo/dojo.js:322
req.getText = function(url, async, onLoad){
var xhr = getXhr();
xhr.open('GET', fixupUrl(url), false);
xhr.send(null);
if(xhr.status == 200 || (!location.host && !xhr.status)){
if(onLoad){
onLoad(xhr.responseText, async);
}
}else{
console.log(xhr.status);//<======== here 0
throw makeError("xhrFailed", xhr.status);
}
return xhr.responseText;
};
Hi @SergKam .. we stumbled upon the same exact issue.. have you found any further information or workarounds in the meantime?
Hi @ariya are the developers aware of this bug? It looks like it's breaking all the synchronous xhr requests (for example used by some versions of dojo framework to load modules)
After further testing, @ariya I can confirm that this issue is not present in v1.9.8 ... so it has been introduced in 2.0 ...
Fixed in master.
I'm using 2.1.3 and I'm still seeing xhr.status of 0 :(
Still seeing this issue in 2.1.1. @Vitallium
Same here. v. 2.1.1
Maybe cross domain requests causes it?
I think I'm seeing this as well in 2.1.1. xhr.status of 0 and responseText of '' despite server logging showing the request/response completes normally. Succeeds > 95% of the time, then just fails at random.
Anyone find a workaround or way to consistently reproduce?
@Vitallium can we reopen this? It appears that it is still occurring. :(
We have a PHP application with an extensive (1000s of test cases) phantomjS-based (casper) test suite. Most of the time, the entire suite will complete successfully, but every once in a while, one of our thousands of AJAX requests will come back with a status code of 0 and an empty response body.
It has happened with a number of different requests yielding widely differing failures. Are there any plans to get to the bottom of this, or does anyone have an idea what might be cause of this?
It's possible that it's working. XHR must return status 0 in the case of an incomplete failed request (when the server didn't have a chance to send back a status yet). The question is, is your situation a valid one, or is Phantom misbehaving? If it is misbehaving, is it XHR or is it the network request failing when it shouldn't?
IMHO PhantomJS is misbehaving. Wireshark shows 404, xhr.status is 0. 100% reproducible. (Five 404->0 requests per try.)
200 works just fine.
(v2.1.1.0; testing a Rails site)
Worked flawlessly with Selenium, but for various reasons we're migrating to PhantomJS.
Well, it seems using another browser (even just for testing) puts it on one's browser compatibility list. :-)
Using Poltergeist with Capybara and encountering this as well. Seems more general than my setup. Are there any current workarounds? Using version 2.1.1 of PhantomJS
issue here too, 2.1.1:
capybara + poltergeist: xhr.status === 0, capybara + chromedriver: xhr.status === 404
Same for mocha-phantomjs.
The statuscode 0 in PhantomJS Version 2.1.1
Please post a small example to reproduce the problem again.
Here's a test case to try to reproduce this adapted from the original post in this issue. I might be doing something wrong but it looks like xhr onreadystatechange isn't holding the correct xhr data in PhantomJS 2.1.1.
server.js (small node server to return 200 for all URLs except /404)
server = require('http').createServer(function(req, res) {
res.statusCode = req.url.indexOf('404') > 0 ? 404 : 200;
res.end();
});
server.listen(3000, function(err) {console.log('server is listening on', 3000)});
start the node server using node server.js
test.js (PhantomJS test case)
var page = require("webpage").create();
page.onConsoleMessage = function(msg) {
console.log(msg);
};
page.onResourceReceived = function(response) {
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
};
page.onResourceRequested = function(requestData, networkRequest) {
console.log('Request (#' + requestData.id + '): ' + JSON.stringify(requestData));
};
page.evaluate(function() {
//to test in your browser, begin copying here...
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3000/should200';
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log('=========== TEST BEGIN =============')
console.log('Status:', xhr.status.toString());
console.log('=========== TEST END =============')
}
};
try {
console.log('loading:', url);
xhr.send(null);
} catch (e) {
console.log('error:', e.toString());
}
//to test in your browser, stop copying here...
});
setTimeout(function() {
phantom.exit();
}, 1000);
run that with phantomjs test.js after making sure the node server is running. You'll see the xhr Status is 0 and the xhr object is empty. To run the same test in your browser, copy just the code inside of page.evaluate, open a new browser tab and navigate to http://localhost:3000 and then open your developer console and paste the code there.
Chrome 53 output:
=========== TEST BEGIN =============
Status: 200
=========== TEST END =============
PhantomJS 2.1.1 output:
=========== TEST BEGIN =============
Status: 0
=========== TEST END =============
You'll even notice that's for a URL that should return a 200 (http://localhost:3000/should200). If you change the URL to http://localhost:3000/should404 then that will return a 404 in Chrome, still 0 in PhantomJS. onResourceReceived seems to work fine in PhantomJS though showing the correct status code.
Confirmed also from me. Currently using 2.1.1
Also just encountered this with PhantomJS 2.1.1. Unfortunately the same problem occurs with capybara-webkit, too. When running with Selenium webdriver, the XHR status code is returned correctly.
Confirmed - I am seeing the same issue via [email protected] -> [email protected] -> [email protected] -> [email protected]
As far as I can tell, when using wireshark, the XHR request never seems to get sent
Could anyone shed some light what's the real problem here? I'm very puzzled how to approach this issue.
When running the spec with selenium, everything is fine. When trying it in the browser, everything is fine. But when running the spec with phantomjs, an ajax:error is raised even before the server had a chance to send a response.
$(document).on 'ajax:error', '...', (request, error)->
console.log JSON.stringify error
The error itself is not very helpful:
{"readyState":0,"status":0,"statusText":"error"}
why is this closed? this is still a bug as of 2.1.7
Most helpful comment
why is this closed? this is still a bug as of 2.1.7