Getting the error text in an XMLHttpRequest error call back - javascript

Given this little snippet of code:
function getPage () {
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("error", getFailed);
xhttp.open("GET", "http://nonexistentserver.com", true);
xhttp.send();
}
function getFailed(msg) {
// I get an ProgressEvent object which doesn't have any text properties?
}
When it runs, the getFailed() callback does indeed get called, but I can't find any information on how to determine what the error was. When I searched for information, all I could find were HTML errors (like 404) and bug reports about causing an error. How do I obtain information about what the failure was available in the error callback?

It seems like in your case it's impossible to get the error information. There are some properties which show the request status: XMLHttpRequest.status, XMLHttpRequest.statusText and XMLHttpRequest.responseText. But they all don't work here (only XMLHttpRequest.status shows '0') in this case. Error event of XMLHttpRequest is called when just error occurs. It doesn't send any information about the error. I hope these will help you: XMLHttpRequest and XMLHttpRequest Properties

You can try to use onprogress event and handle the status code, like this:
var xhr = new XMLHttpRequest;
xhr.onprogress = function () {
console.log(xhr.status); //404 will be printed on console
};
xhr.open('GET', '/noexists');
xhr.send();

In the getFailed call:
function getFailed(e) {
console.log('response error:', e.currentTarget.response);
}
The e.currentTarget is the same xhr instance.

Related

Fetching error gives more information on error in console than in catch method [duplicate]

I wrote a function that keeps returning an Access-Control-Allow-Origin error. This is actually fine for me; I don't want to fix this. I just want to catch it so I can read its message in my program.
All the code that causes the error to be thrown is within my try block, and my catch block displays the error's string message. However, when I run the code, no error is caught, and the error shows up in red in the console. How do I catch this error and store its message?
try {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if (this.status < 400 && this.status >= 300) {
console.log('this redirects to ' + this.getResponseHeader("Location"));
} else {
console.log('doesn\'t redirect');
}
}
xhr.open('HEAD', $scope.suggLink, true);
xhr.send();
} catch(e) {
console.log('Caught it!');
console.log(e.message);
}
While browsers will log a more-detailed error message to the console, you can’t access that from your code. See https://bugs.chromium.org/p/chromium/issues/detail?id=118096#c5:
The details of errors of XHRs and Fetch API are not exposed to JavaScript for security reasons.
As far as the what specs actually require here, the Fetch spec is what defines the details of the “status message” to provide in case of an error — even if XHR is used instead of the Fetch API (the XHR spec references the Fetch spec). And for any network error or response blocked by the browser, the Fetch spec requires that the status message be “the empty byte sequence”:
A network error is a response whose status is always 0, status message is always the empty byte sequence, header list is always empty, body is always null, and trailer is always empty.
So all you can get back from any error you can catch is “TypeError: Failed to fetch” or such.
If you’re using XHR, all you have for handling an error is the onerror event handler:
xhr.onerror = function() { console.log("Error occurred but I dunno what exactly.")}
jquery version of above (sideshowbarker's) workaround for CORS error:
let sURL = 'https://www.mocky.io/v2/5185415ba171ea3a00704eed';
$.getJSON(sURL, function (json)
{
console.log('json from web-service ->', json);
})
.fail(function()
{
console.log("error - could not get json data from service");
});

How to get error information in XmlHttpRequest error event

I have simple code like that:
const request = new XMLHttpRequest();
request.addEventListener('error', logError);
request.open('GET', 'www.someapi.com');
request.withCredentials = true;
request.send();
And logging is like that:
const logError = (error) => {
console.log(`Error\nEvent:\n${JSON.stringify(error, null, 4)}`);
// Code to log to server
};
Now what happens is that I get log messages with error, but there is like nothing meaningful in there, just "isTrusted": true. I would like to get more information on what is going on and why I get this error. E.g. in the console I see something like that when I fiddle connection drop:
net::ERR_CONNECTION_RESET
But when it comes to javascript event, it's literally no meaningful information to figure out what is going on. E.g. I have read that CORS can cause it here, but without any message it is very hard to figure out what is going on.
You can check the error log as follow :
const request = new XMLHttpRequest();
request.onerror = function (e) {
console.log(e);
reject(new TypeError('Network request failed'));
};

Shouldn't the error event of xmlhttprequest have an error message?

I'm working on making an AJAX request from a Firefox extension. I have this code:
function GetMenu(){
var oReq = Components.classes["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance();
// Setup event handlers - must be set before calling open()
oReq.addEventListener("progress", updateProgress, false);
oReq.addEventListener("load", transferComplete, false);
oReq.addEventListener("error", transferFailed, false);
oReq.addEventListener("abort", transferCanceled, false);
oReq.open('POST', "http://www.foo.bar/", true);
oReq.send('your=data&and=more&stuff=here');
}
function transferFailed(evt) {
Application.console.log("An error occurred while transferring the file.");
Application.console.log(this.responseText);
for(var i in evt)
Application.console.log(i+ ' => '+evt[i]);
}
The request fails because http://www.foo.bar/ does not exist (I assume). My question is, why is there no error message in the evt object passed to transferFailed() that says, "The domain does not exist" or "DNS failure" or something of that nature? None of the event object's properties have any indication of what the problem is, no message, no error code, etc.
Shouldn't there be some sort of indication of what the actual error is?
Since you're running with chrome-privileges:
function transferFailed(evt) {
if (this.channel && this.channel.status == Components.results.NS_ERROR_UNKNOWN_HOST) {
alert("DNS error");
}
}
(what #paa said in the comment).
See (you might need to QueryInterface/instanceof accordingly):
nsIRequest
nsIChannel
nsIHttpChannel
nsIHttpChannelInternal
Network errors are not propagated to the caller.
status (and statusText, though it's whatever the server likes) is about HTTP.

XmlHttpRequest.onload not called

I'm playing around with this XmlHttpRequest thing. In some tutorials and books, it is the onload function the one that is called when the request is done. In my little experiment, this function is never called. Here's my code:
window.onload = function() {
var url = "http://www.google.com";
var request = new XMLHttpRequest();
request.onload = function() {
var state = this.readyState;
var responseCode = request.status;
console.log("request.onload called. readyState: " + state + "; status: " + responseCode);
if (state == this.DONE && responseCode == 200) {
var responseData = this.responseText;
alert("Success: " + responseData.length + " chars received.");
}
};
request.error = function(e) {
console.log("request.error called. Error: " + e);
};
request.onreadystatechange = function(){
console.log("request.onreadystatechange called. readyState: " + this.readyState);
};
request.open("GET", url);
request.send(null);
};
I'm testing this on the last Firefox release (just updated today). The log line in onload is never printed, and the breakpoint I set in the first line is never hit. However, the onreadystatechange function is called twice, and the http request is actually made. This is what firebug's console shows:
request.onreadystatechange called. readyState: 1
GET http://www.google.com/ 302 Found 174ms
request.onreadystatechange called. readyState: 4
NS_ERROR_FAILURE: Failure
request.send(null);
There's an error in the send line. I've tried changing it to request.send() with identical result.
At first I thought this might be the browser trying to prevent XSS, so I moved my html driver page to a Tomcat instance in my dev machine, but the result is the same.
Is this function guaranteed to be called? As I've said above, it's common to be seen in most tutorials, but on the other hand in the W3C spec page, the hello world snippet uses onreadystatechange instead:
function processData(data) {
// taking care of data
}
function handler() {
if(this.readyState == this.DONE) {
if(this.status == 200 &&
this.responseXML != null &&
this.responseXML.getElementById('test').textContent) {
// success!
processData(this.responseXML.getElementById('test').textContent);
return;
}
// something went wrong
processData(null);
}
}
var client = new XMLHttpRequest();
client.onreadystatechange = handler;
client.open("GET", "unicorn.xml");
client.send();
It checks readyState == this.DONE. DONE has the value 4, which is what I can see in my log. So if this were a XSS related issue, and the browser were preventing me to make the connection to a different domain, then why the actual connection is made and the DONE status is received???
PS: Yes, I know there are powerful libraries to do this easily, but I'm still a JavaScript noob so I'd like to understand the low level first.
UPDATE:
I've changed the URL to one inside my domain (localhost), and the error is gone but the onload function is still not being called. Tested in IE8 and does not work. Tested in Chrome and works. How's that?
UPDATE 2:
Tested again in Firefox, and now it works. Probably the old page was still cached so that's why I couldn't notice it immediatly. Still failing in IE8, I'll try to test it in a newer version.
It looks like it was indeed a XSS issue and Firefox was blocking the onload call. I can't still understand why the http network request was actually being done and the onreadystatechange was being called with the DONE readyState.
I changed the URL to another one in the same domain, and now it works in Firefox (after some cache-related false attempts) and in Chrome. It still does not work in IE8, despite the official docs say it is supported. I've found this SO answer which states otherwise. It looks like the onload function is a more modern convenience method and the old way of checking the result is using onreadystatechange instead.
I guess I'll accept this answer as the solution unless a more detailed answer is provided.
The onload handler won't be called for yet another reason, I'm adding it here just so it can be helpful to someone else referencing this page.
If the HTTP response is malformed, the onload handler will not be called either. For example, a plaintext response of 10 bytes that advertises a length of 14 in Content-Length header will not invoke the onload handler. I wasted hours on client code before I start to replace back-end units with test stubs.
IE has different method to create xmlhttprequest.
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
};
same this article:https://www.html5rocks.com/en/tutorials/cors/

issue with XMLHttpRequest - returning status of 0 on local machine and live server

i am having trouble getting this XMLHttpRequest to work properly, this is my first time using ajax so i'm not sure if i'm formatting everything correctly. i have looked all over the web and i keep finding basically the same info and examples but certain elements are in different orders so i'm not sure which is correct and i've tried them all and nothing seems to work. here is my code:
function ajaxRequest(){
var activexmodes=["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"]
if (window.XMLHttpRequest)
return new XMLHttpRequest()
else if (window.ActiveXObject){
for (var i=0; i<activexmodes.length; i++){
try{
return new ActiveXObject(activexmodes[i])
}
catch(e){
//suppress error
}
}
}
else
return false
}
function getData(fileName){
var fileLoc =encodeURI("assets/"+fileName+".html")
alert(fileLoc)
var request = new ajaxRequest()
request.open("GET",fileLoc,true)
var response = request.responseText
alert(request.status)
alert(response)
request.send(null)
return response
}
function home() {
var data = getData("home")
var contentDiv = document.getElementByClassName(content)
contentDiv.innerHTML = data;
}
home is triggered when the user clicks on a div in the page. i know that getData is being accessed because the alerts pop up, however i get a status code of 0, this happened on both my local machine and on a live server. i read that localhosts can throw a 0 status regardless of the actual status but its happening on a live server as well. if someone could help me fix this issue and/or clarify the correct order of events in the function i would greatly appreciate it.
EDIT:
new code:
function getData(fileName){
fileLoc = encodeURI("assets/"+fileName+".html")
alert(fileLoc);
request.onreadystatechange = processData;
request.open("GET",fileLoc, false);
request.send();
alert(request.readyState);
alert(response);
}
function processData(){
if (request.readyState==4){
if (request.status==200){
document.getElementsByClassName('content').innerHTML = request.responseText;
}
else{
alert("An error has occured making the request");
}
}
}
You are telling XMLHTTPRequest to send the request asynchronous, which means the rest of your script gets executed while you wait for the response. You will get a reponse code 0 (uninitialized) and an empty response, because at the time you return from the function that is the current status and response.
Instead you want to define a function to call when the state changes, or let XMLHTTPRequest work synchronous.
Please refer to this tutorial for a simple example that should help you out.

Categories