Catch asynchronous network error from XMLHttpRequest send()

19,105

Solution 1

Use the onerror event of the XMLHttpRequest:

function aGet(url, cb) {
    var x = new XMLHttpRequest();
    x.onload = function(e) {
        cb(x.responseText)
    };
    x.onerror= function(e) {
        alert("Error fetching " + url);
    };
    x.open("GET", url, true);
    x.send();
}

var dmp = console.log.bind(console); // Dummy callback to dump to console
aGet("/", dmp) // Ok, uses onload to trigger callback
aGet("http://dgfgdf.com/sdfsdf", dmp); // Fails, uses onerror to trigger alert

Solution 2

I wrote a full solution to that problem. It works perfectly!
I have a function called networkOrfail which will try to resend the XMLHttpRequest each second, if the network is available. Otherwise, it'll ignore the request.
When the request is succeeded, that polling stops and the response is returned.

Here's how to detect whether the network is available:

function getNavigatorConection() {
    return navigator.onLine;
}

Then, create your XMLHttpRequest:

function makeRequest() {
    let xhr = new XMLHttpRequest();
    xhr.open('GET', 'anypage/anotherpage', true);
    xhr.timeout = 2000;
    xhr.onload = function () {
        // Your request is completed
        if (xhr.readyState == 4 && xhr.status == 200) {
            // You're in a successfully condition
        }
    };
    xhr.ontimeout = function (e) {
        // Your request timed out
    };
    xhr.send(null);
}

Now, define your polling method as follows:

function networkOrFail(callFunc, callTime) {
    let connected = getNavigatorConection();
    let callableTimes = callTime < 2000 ? 2000 : callTime;
    let toursBegin = 3;
    let tours = toursBegin;
    let intervalId;
    let request = function() {
        intervalId = setInterval(function() { 
        let connected = getNavigatorConection();
        if (tours > 0) {
            if (connected) {
                callFunc();
                tours =0;
                return false;
            }
            tours--;
            alert("i tryied againt to resend for another time and it remain just "+tours+" to retry");
        } else {
            clearRequest();
            tours =toursBegin;
        }
    }, callableTimes > 5000 ? 5000 : callableTimes);

    };
    let clearRequest = function() {
        clearInterval(intervalId);
        intervalId = null;
    };
    if (connected)
        callFunc();
    else
        request();
}

Finally, call the send method through the polling method by passing it toghether with the timeout in minutes:

networkOrFail(makeRequest, 5000);
Share:
19,105
rustybeanstalk
Author by

rustybeanstalk

Updated on July 24, 2022

Comments

  • rustybeanstalk
    rustybeanstalk almost 2 years

    I'm making an http request asynchronously using XMLHttpRequest:

    xhr.open(method, uri, true);
    

    When I send something:

    xhr.send(something)
    

    When the server is down, it throws the following error:

    net::ERR_CONNECTION_REFUSED
    

    How can I catch and handle this error? The standard try..catch block doesn't work as the request is asynchronous.

    Thanks in advance.

  • rustybeanstalk
    rustybeanstalk over 9 years
    I was under the impression that this is only supported Chrome, Safari & Firefox, but not in Opera or various mobile browsers. Do you know what the support is for onerror? Thanks.
  • dandavis
    dandavis over 9 years
    looks pretty solid: caniuse.com/#feat=xhr2, plus msdn.microsoft.com/en-us/library/ie/cc288060(v=vs.85).aspx you'll have to roll the two into one to hit 95%, but that's vanilla for ya!
  • generalchaos
    generalchaos over 9 years
    This is not working for me. I am trying to make a PUT request and when the server returns an error, neither xhr.onerror or xhr.upload.error handlers are catching the error. Having the error propagate to the browser is causing other javascript issues.
  • Tengiz
    Tengiz over 8 years
    still throws a nasty error in the console. Any way to prevent that?