'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 1:[1]

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.

Solution 2:[2]

You could add a script tag with a src attribute referencing a file you know exists on the server and then using the onerror event to detect if it is not found:

<script src="nonexistent.js" onerror="alert('error!')"></script>

Credit to last comment of this answer.

You shouldn't run into cross origin issues using this solution.

Update

If you don't want to take the chance and run scripts you can use the img tag instead. Use the onerror event to detect failure and the onload event to detect success:

<html>
    <head>
        <img src="https://www.google.com/images/srpr/logo3w.pngx" onerror="failure()" onload="success()" height="0" width="0">
        <script>
            let _isSuccess = false;
            function success() {
                _isSuccess = true;
            }

            function failure() {
                _isSuccess = false;
            }

            function isSuccess() {
                console.log(`is success == ${_isSuccess}`);
                return _isSuccess;
            }

        </script>
    </head>
    <body onload="isSuccess()">
        <h1>Hello World!</h1>
    </body>
</html>

Solution 3:[3]

Would this suffice? You can't have asynchronous functions (onerror/onload) return values. Instead, you can do something similar to callbacks.

function conditional(status){
  if(status)
  {
    console.log("Hey, the image loaded correctly.");
  }
  else
  {
    console.log("Bruh, the server is dead.");
  }
}

var tester = new Image();
tester.onload = function() {
  conditional(true);
};
tester.onerror = function() {
  conditional(false);
};
tester.src="https://i.imguhr.com/Ru1q3sS.jpg";

https://jsbin.com/veruzegohe/1/edit?html,console,output

Solution 4:[4]

This isn't possible. It would allow for information, that the same origin policy is designed to protect, to leak.

e.g. Does the company that the user works for, have an intranet page with a particular URL?

This could lead to such things as determining which version of Microsoft Sharepoint (to pick a well known example) the company uses, what URL it is installed on, and then using that information for a social engineering attack.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kaiido
Solution 2 Community
Solution 3 General Grievance
Solution 4 Quentin