Est-il possible d'envoyer un ping à un serveur à partir de Javascript?


152

Je crée une application Web qui nécessite de vérifier si les serveurs distants sont en ligne ou non. Lorsque je l'exécute à partir de la ligne de commande, le chargement de ma page atteint 60 s (pour 8 entrées, il sera mis à l'échelle linéairement avec plus).

J'ai décidé d'emprunter la voie du ping du côté de l'utilisateur. De cette façon, je peux charger la page et leur demander d'attendre les données "le serveur est en ligne" tout en parcourant mon contenu.

Si quelqu'un a la réponse à la question ci-dessus, ou s'il connaît une solution pour que ma page se charge rapidement, je l'apprécierais certainement.

Réponses:


134

J'ai trouvé quelqu'un qui accomplit cela avec une utilisation très intelligente de l' Imageobjet natif .

De leur source, c'est la fonction principale (elle a des dépendances sur d'autres parties de la source mais vous voyez l'idée).

function Pinger_ping(ip, callback) {

  if(!this.inUse) {

    this.inUse = true;
    this.callback = callback
    this.ip = ip;

    var _that = this;

    this.img = new Image();

    this.img.onload = function() {_that.good();};
    this.img.onerror = function() {_that.good();};

    this.start = new Date().getTime();
    this.img.src = "http://" + ip;
    this.timer = setTimeout(function() { _that.bad();}, 1500);

  }
}

Cela fonctionne sur tous les types de serveurs que j'ai testés (serveurs Web, serveurs ftp et serveurs de jeux). Cela fonctionne également avec les ports. Si quelqu'un rencontre un cas d'utilisation qui échoue, veuillez poster dans les commentaires et je mettrai à jour ma réponse.

Mise à jour : le lien précédent a été supprimé. Si quelqu'un trouve ou met en œuvre ce qui précède, veuillez commenter et je l'ajouterai dans la réponse.

Mise à jour 2 : @trante était assez gentil pour fournir un jsFiddle.

http://jsfiddle.net/GSSCD/203/

Mise à jour 3 : @Jonathon a créé un dépôt GitHub avec l'implémentation.

https://github.com/jdfreder/pingjs

Mise à jour 4 : il semble que cette implémentation n'est plus fiable. Les gens signalent également que Chrome ne prend plus en charge tout cela, ce qui génère une net::ERR_NAME_NOT_RESOLVEDerreur. Si quelqu'un peut vérifier une autre solution, je la placerai comme réponse acceptée.


48
C'est ce que j'utilise. Il a cependant un défaut, c'est que "l'image" est mise en cache. Lorsque je cingle une adresse IP donnée au départ, j'obtiens 304 ms - mais si je lui envoie un ping une deuxième fois sans rechargement de page, j'obtiens 2 ms à la place. Cela pourrait être évité en ajoutant un "/?cachebreaker="+new Date().getTime();à la fin de l'img src si nécessaire.
Meshaal

2
cela ne fonctionne pas pour moi, un nom d'hôte incorrect connu entraîne une requête Ping introuvable .... mais comme une erreur est `` bonne '', cette chose dit qu'elle a répondu
Maslow

5
D'autres tests ont révélé que cela n'est absolument pas fiable.
Leo

2
L'API Ping créée par @Jonathon envoie un ping à tout. Sites inexistants et personnages aléatoires.
IE5Master

2
L'API Ping échoue toujours avec une erreur. CEPENDANT, si l'URL cible dénote une image, elle déclenche onload, ce qui est génial! Contourne les contrôles CORS.
Martin Vysny le

20

Ping est ICMP, mais s'il y a un port TCP ouvert sur le serveur distant, cela peut être réalisé comme ceci:

function ping(host, port, pong) {

  var started = new Date().getTime();

  var http = new XMLHttpRequest();

  http.open("GET", "http://" + host + ":" + port, /*async*/true);
  http.onreadystatechange = function() {
    if (http.readyState == 4) {
      var ended = new Date().getTime();

      var milliseconds = ended - started;

      if (pong != null) {
        pong(milliseconds);
      }
    }
  };
  try {
    http.send(null);
  } catch(exception) {
    // this is expected
  }

}


J'aime cette solution délicate. Devoir fournir une fonction pour pong au lieu de renvoyer un nombre est un peu étrange pour moi mais réalisable.
Nick

@armen: vous devez fournir une fonction comme troisième argument de ping (), la valeur de cet argument est appelée pong dans la fonction.
finitud

2
ping("example.com", "77", function(m){ console.log("It took "+m+" miliseconds."); })..... exemple d'appel
jave.web

@Nick: Il s'agit de trucs asynchrones, donc au moment où la méthode revient, le onreadystatechangen'a pas encore été déclenché. Cela signifie que vous avez besoin d'un rappel à récupérer lorsque l'état change.
awe

Quoi que je choisisse pour l'hôte, pong () est appelé. ping ( test.zzzzzzzzz, "77", function (m) {console.log ("Cela a pris" + m + "millisecondes.");}) affiche "Cela a pris 67 millisecondes." ping ( stackoverflow.com, "80", function (m) {console.log ("Cela a pris" + m + "millisecondes.");}) donne une erreur CORS: developer.mozilla.org/en-US/docs/Web/ HTTP / CORS / Erreurs /… Je ne vois pas comment je peux vérifier avec ce code si un ordinateur distant est en ligne.
Tux

18

vous pouvez essayer ceci:

mettez ping.html sur le serveur avec ou sans contenu, sur le javascript, faites la même chose que ci-dessous:

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>

1
Les serveurs auxquels je fais un ping ne sont pas les miens, donc je n'ai pas cette option. Merci quand même.
Chuck Callebs

9
@dlchambers Non pas en raison de CORS mais EN RAISON DE LA POLITIQUE TRANSFRONTALIÈRE. CORS permet à un serveur de spécifier les origines et il doit être pris en charge par le navigateur. il s'agit donc plutôt d'un problème interdomaine.
Royi Namir

Les requêtes de type HEAD ne fonctionneront pas non plus à cause de CORS. Testé avec Chromium 55. Réception de la même erreur avec le code http 0 que dans le cas de net :: CONNECTION_REFUSED par exemple.
Martin Vysny

Ceci est plus convivial pour tous les navigateurs.
Gabriel

14

Vous ne pouvez pas directement "ping" en javascript. Il peut y avoir plusieurs autres façons:

  • Ajax
  • Utilisation d'une applet Java avec isReachable
  • Ecrire un script côté serveur qui pings et utiliser AJAX pour communiquer avec votre script serveur
  • Vous pourrez peut-être également envoyer un ping en flash (actionscript)

1
L'isReachable de Java n'est pas très fiable ... Mais bon, c'est 2018 et les applets Java sont de toute façon obsolètes.
dreua

8

Vous ne pouvez pas faire de ping régulier dans le Javascript du navigateur, mais vous pouvez savoir si le serveur distant est actif en chargeant par exemple une image depuis le serveur distant. Si le chargement échoue -> serveur arrêté.

Vous pouvez même calculer le temps de chargement en utilisant onload-event. Voici un exemple d'utilisation de l'événement onload.


4
Ce qui est malheureux, c'est que les serveurs auxquels je fais un ping ne sont pas des serveurs Web. Ce sont des serveurs de jeux.
Chuck Callebs

1
Ensuite, vous devez faire le ping côté serveur - ou vous pouvez envisager un serveur http léger.
Epeli

Connaissez-vous un moyen d'effectuer des pings agrégés? C'est mon principal ralentissement, attendre qu'une demande se termine avant que l'autre ne commence.
Chuck Callebs

Vous devez envoyer une requête ping aux serveurs simultanément. Vous pouvez y parvenir avec select, threads ou processus. Pour une solution vraiment hardcore, vous pouvez utiliser Eventmachine.
Epeli

1
Vous pourriez envisager de tirer parti de la commande de ligne de pingcommande. C'est la force industrielle. Ou, il existe toutes sortes d'applications gratuites / open-source pour surveiller si un hôte est en cours d'exécution, en utilisant divers types de vérifications de pulsations.
the Tin Man

7

Pitching in with a websocket solution ...

function ping(ip, isUp, isDown) {
  var ws = new WebSocket("ws://" + ip);
  ws.onerror = function(e){
    isUp();
    ws = null;
  };
  setTimeout(function() { 
    if(ws != null) {
      ws.close();
      ws = null;
      isDown();
    }
  },2000);
}

L' isUp();appel ne devrait-il pas être dans le onopengestionnaire d'événements? :)
jave.web

1
Il utilise le protocole websocket mais suppose qu'il n'y a pas réellement de serveur websocket en attente d'une connexion. C'est juste pour envoyer un ping à «n'importe quelle ancienne adresse IP».
Antony Woods

Mais comment pouvez-vous détecter si WebSocket n'est tout simplement pas pris en charge ou s'il y a vraiment eu une erreur? :)
jave.web

Si vous pensez que vous serez assez malchanceux pour envoyer un ping à une IP qui pourrait accepter une connexion Websocket sur le port 80, alors oui, vous devriez également ajouter isUp();à ce rappel. Ou atténuez cela en ajoutant un port distinctement non-websocket-y.
Antony Woods

J'ai voté pour cela parce que je suis venu ici à la recherche d'une solution à ce qui se passe lorsque mon serveur websocket est redémarré, et cette réponse m'a montré que je pouvais définirTimeout dans le gestionnaire d'erreurs du socket et tenter de me reconnecter (attente occupée). Probablement pas la meilleure pratique, mais résout mon problème. :)
mynameisnafe

6

Pour garder vos demandes rapides, mettez en cache les résultats côté serveur du ping et mettez à jour le fichier ping ou la base de données toutes les deux minutes (ou quelle que soit la précision que vous souhaitez). Vous pouvez utiliser cron pour exécuter une commande shell avec vos 8 pings et écrire la sortie dans un fichier, le serveur Web inclura ce fichier dans votre vue.


Je pense que c'est le moyen le plus fiable avec le meilleur résultat possible. Cependant, comme cela nécessite encore des travaux sur le serveur, je dirais que ce n'est pas une manière intelligente.
Chetabahana

5

Si vous essayez de voir si le serveur "existe", vous pouvez utiliser ce qui suit:

function isValidURL(url) {
    var encodedURL = encodeURIComponent(url);
    var isValid = false;

    $.ajax({
      url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
      type: "get",
      async: false,
      dataType: "json",
      success: function(data) {
        isValid = data.query.results != null;
      },
      error: function(){
        isValid = false;
      }
    });

    return isValid;
}

Cela renverra une indication vrai / faux si le serveur existe.

Si vous souhaitez un temps de réponse, une légère modification fera

function ping(url) {
    var encodedURL = encodeURIComponent(url);
    var startDate = new Date();
    var endDate = null;
    $.ajax({
      url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + encodedURL + "%22&format=json",
      type: "get",
      async: false,
      dataType: "json",
      success: function(data) {
        if (data.query.results != null) {
            endDate = new Date();
        } else {
            endDate = null;
        }
      },
      error: function(){
        endDate = null;
      }
    });

    if (endDate == null) {
        throw "Not responsive...";
    }

    return endDate.getTime() - startDate.getTime();
}

L'usage est alors trivial:

var isValid = isValidURL("http://example.com");
alert(isValid ? "Valid URL!!!" : "Damn...");

Ou:

var responseInMillis = ping("example.com");
alert(responseInMillis);

Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change.
vonbrand

1
c'est une excellente solution, mais malheureusement, le service de requête de domaine Yahoo semble donner des résultats variables. par exemple, si vous essayez les URL suivantes, commencez le téléchargement .com beginfreedownload .com elles reviennent comme non enregistrées, mais si vous accédez à ces URL, elles sont clairement enregistrées. une idée de ce qui se passe ici? (J'ai ajouté un espace aux noms de domaine dans ces exemples, juste pour éviter de donner du jus de google. dans mon test, je
n'avais

Vous faites une demande à Yahoo! API, le ping ne sera même pas le même si vous faites une requête depuis votre machine. Cela n'a aucun sens
Andre Figueiredo

Ce No 'Access-Control-Allow-Origin' header is present on the requested resource. Originrappel des causes et du succès n'est jamais appelé
vladkras


4

Il y a beaucoup de réponses folles ici et en particulier sur CORS -

Vous pouvez faire une requête http HEAD (comme GET mais sans charge utile). Voir https://ochronus.com/http-head-request-good-uses/

Il n'a PAS besoin d'une vérification avant le vol, la confusion est due à une ancienne version de la spécification, voir Pourquoi une demande HEAD d'origine croisée a-t-elle besoin d'une vérification avant vol?

Vous pouvez donc utiliser la réponse ci-dessus qui utilise la bibliothèque jQuery (je ne l'ai pas dit) mais avec

type: 'HEAD'

--->

<script>
    function ping(){
       $.ajax({
          url: 'ping.html',
          type: 'HEAD',
          success: function(result){
             alert('reply');
          },     
          error: function(result){
              alert('timeout/error');
          }
       });
    }
</script>

Bien sûr, vous pouvez également utiliser vanilla js ou dojo ou autre chose ...


1
L'envoi de la demande HEAD échoue toujours avec "XMLHttpRequest ne peut pas charger IP. Aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée. L'origine 'ip2' n'est donc pas autorisée à accéder." Donc bloqué par CORS. Vous obtiendrez le succès avec le statut http 0, et vous ne pourrez donc pas le différencier de net :: ERR_CONNECTION_REFUSED par exemple
Martin Vysny

0

Je ne sais pas quelle version de Ruby vous utilisez, mais avez-vous essayé d'implémenter ping pour ruby ​​au lieu de javascript? http://raa.ruby-lang.org/project/net-ping/


Ouais, j'ai essayé mais les pings sont toujours revenus faux, quel que soit le serveur Web. Je l'ai changé pour n'utiliser que la ping server.comsyntaxe.
Chuck Callebs

-1
let webSite = 'https://google.com/' 
https.get(webSite, function (res) {
    // If you get here, you have a response.
    // If you want, you can check the status code here to verify that it's `200` or some other `2xx`.
    console.log(webSite + ' ' + res.statusCode)
}).on('error', function(e) {
    // Here, an error occurred.  Check `e` for the error.
    console.log(e.code)
});;

si vous exécutez ceci avec node, il consignera le journal 200 tant que Google n'est pas en panne.


non, ce n'est pas ... 1) il vous manque, 2) il revient 301 Déplacé de façon permanente: D
Michal Miky Jankovský

-1
const ping = (url, timeout = 6000) => {
  return new Promise((reslove, reject) => {
    const urlRule = new RegExp('(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]');
    if (!urlRule.test(url)) reject('invalid url');
    try {
      fetch(url)
        .then(() => reslove(true))
        .catch(() => reslove(false));
      setTimeout(() => {
        reslove(false);
      }, timeout);
    } catch (e) {
      reject(e);
    }
  });
};

utiliser comme ceci:

ping('https://stackoverflow.com/')
  .then(res=>console.log(res))
  .catch(e=>console.log(e))

-4

Vous pouvez exécuter la commande DOS ping.exe à partir de javaScript en utilisant les éléments suivants:

function ping(ip)
{
    var input = "";
    var WshShell = new ActiveXObject("WScript.Shell");
    var oExec = WshShell.Exec("c:/windows/system32/ping.exe " + ip);

    while (!oExec.StdOut.AtEndOfStream)
    {
            input += oExec.StdOut.ReadLine() + "<br />";
    }
    return input;
}

Est-ce ce qui a été demandé ou est-ce que je manque quelque chose?


4
Cela ne fonctionnera malheureusement que sur IE et uniquement sur un serveur Windows. Une meilleure option serait d'utiliser AJAX pour exécuter un script côté serveur.
Andrew Grothe

Que diable? Les objets Active X peuvent s'exécuter dans le système de fichiers de l'utilisateur (dans IE sur le serveur win)? Je n'avais pas travaillé avec ActiveX mais je n'imaginais pas que ...
Julix

-6

juste remplacer

file_get_contents

avec

$ip = $_SERVER['xxx.xxx.xxx.xxx'];
exec("ping -n 4 $ip 2>&1", $output, $retval);
if ($retval != 0) { 
  echo "no!"; 
} 
else{ 
  echo "yes!"; 
}

1
Vous devriez modifier votre réponse précédente au lieu d'en ajouter une nouvelle «partielle».
Artemix

-8

Cela pourrait être beaucoup plus facile que tout ça. Si vous voulez que votre page se charge, puis vérifiez la disponibilité ou le contenu d'une page étrangère pour déclencher une autre activité de page Web, vous pouvez le faire en utilisant uniquement javascript et php comme celui-ci.

yourpage.php

<?php
if (isset($_GET['urlget'])){
  if ($_GET['urlget']!=''){
    $foreignpage= file_get_contents('http://www.foreignpage.html');
    // you could also use curl for more fancy internet queries or if http wrappers aren't active in your php.ini
    // parse $foreignpage for data that indicates your page should proceed
    echo $foreignpage; // or a portion of it as you parsed
    exit();  // this is very important  otherwise you'll get the contents of your own page returned back to you on each call
  }
}
?>

<html>
  mypage html content
  ...

<script>
var stopmelater= setInterval("getforeignurl('?urlget=doesntmatter')", 2000);

function getforeignurl(url){
  var handle= browserspec();
  handle.open('GET', url, false);
  handle.send();
  var returnedPageContents= handle.responseText;
  // parse page contents for what your looking and trigger javascript events accordingly.
  // use handle.open('GET', url, true) to allow javascript to continue executing. must provide a callback function to accept the page contents with handle.onreadystatechange()
}
function browserspec(){
  if (window.XMLHttpRequest){
    return new XMLHttpRequest();
  }else{
    return new ActiveXObject("Microsoft.XMLHTTP");
  }
}

</script>

Ça devrait le faire.

Le javascript déclenché doit inclure clearInterval (stopmelater)

Laissez-moi savoir si cela fonctionne pour vous

Jerry


2
Comme je l'ai déjà dit, ce ne sont pas des serveurs Web que je ping. Ce sont des serveurs de jeux. Ils ne répondront pas aux requêtes HTTP. :(
Chuck Callebs

mec, remplacez simplement file_get_contents par
Jerry Wickey

$ ip = $ _SERVER ['127.0.0.1']; exec ("ping -n 4 $ ip 2> & 1", $ sortie, $ retval); if ($ retval! = 0) {echo "non!"; } else {echo "oui!"; }
Jerry Wickey

4
Ce n'est pas une question PHP. C'est une question JavaScript. Je n'utilise pas PHP.
Chuck Callebs

1
Veuillez ne pas utiliser de signatures ou de slogans dans vos messages, sinon ils seront supprimés. Consultez la FAQ pour plus de détails.
Artemix

-13

Vous pouvez essayer d'utiliser PHP dans votre page Web ... quelque chose comme ceci:

<html><body>
<form method="post" name="pingform" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<h1>Host to ping:</h1>
<input type="text" name="tgt_host" value='<?php echo $_POST['tgt_host']; ?>'><br>
<input type="submit" name="submit" value="Submit" >
</form></body>
</html>
<?php

$tgt_host = $_POST['tgt_host'];
$output = shell_exec('ping -c 10 '. $tgt_host.');

echo "<html><body style=\"background-color:#0080c0\">
<script type=\"text/javascript\" language=\"javascript\">alert(\"Ping Results: " . $output . ".\");</script>
</body></html>";

?>

Ce n'est pas testé, il peut donc y avoir des fautes de frappe, etc. mais je suis convaincu que cela fonctionnerait. Pourrait être amélioré aussi ...


5
Selon les balises de l'OP, il s'agit en fait d'une question Ruby on Rails, donc utiliser PHP n'est pas une bonne solution.
the Tin Man

1
Pas pour commencer une dispute ici mais le but de ce forum n'est-il pas d'aider?
Chris

5
@Chris Oui, mais quel genre d'aide avez-vous donné à OP qui utilise Ruby et JS dans son applicatoin en fournissant du code PHP?
biphobe
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.