Search code examples
javascripthttpaccess-control

Check if online resource is reachable with JavaScript, not requiring the The Same Origin Policy to allow it


I want to check if a server is reachable with a JavaScript function.

By reachable, I mean, if the server answers, I don't care which HTTP status code, it's reachable.

Stackoverflow/Google helped me to this function:

function check(target)
{
    var xhr = new XMLHttpRequest();
    var target = "https://"+target+"/index.php";
    var num = Math.round(Math.random() * 10000);

    xhr.open("HEAD", target + "?num=" + num, true);
    xhr.send();
    xhr.addEventListener("readystatechange", processRequest, false);

    function processRequest(e)
    {
      if (xhr.readyState == 4)
      {
        if (xhr.status !== 0)
        {
          return true;
        }
        else
        {
          return false;
        }
      }
    }
}

Which works just fine, if the target allows the action with Access-Control-Allow-Origin: * (or the client specifically). But that is not the case.

I've come across a number of solutions, which all seem to rely on that.

How can I check if a server is reachable, independent of the Access-Control-Allow-Origin settings on the server, with JavaScript?

edit: I just wanted to add, that I can not modify the target (e.g. change headers), but I'm able to identify resources that are supposed to be available (e.g. https://target/this-specific-site.php)

edit2: I'm trying to implement a solution, as suggested by @Vic; try it here:

function chk(){

var img = new Image();   // Create new image element

img.onload = function(){
    return false;
};

img.onerror = function() {
    return true;
};

// Try to change this URL to nonexistant image
img.src = 'https://www.google.com/images/srpr/logo3w.png'; // Set source path

}

if (chk())
{
alert("IMAGE LOADED");
}
else
{
alert("IMAGE FAILED TO LOAD ("+chk()+")");
}

but the function appears to return undefined, so the check fails.

edit3: I need the function to give me a return value.


Solution

  • In modern browsers, you can use the fetch API and its no-cors request Mode which will return an opaque response (you won't be able to do anything else from it) :

    fetch('http://google.com', {mode: 'no-cors'}).then(r=>{
      console.log('google is reachable');
      })
      .catch(e=>{
        console.log('google is not there');
        });
    fetch('http://fakeservertahtdoesntexist.com', {mode: 'no-cors'}).then(r=>{
      console.log('fake is reachable');
      })
      .catch(e=>{
        console.log('fake is not there');
        });

    Weirdly enough, my FF doesn't throw though (but it doesn't then either), while my chrome does throw.