web-dev-qa-db-fra.com

Méthode préférée Java pour envoyer une requête ping à une URL HTTP pour la disponibilité

J'ai besoin d'une classe de moniteur qui vérifie régulièrement si une URL HTTP donnée est disponible. Je peux m'occuper de la partie "régulièrement" en utilisant l'abstraction de Spring TaskExecutor, ce n'est donc pas le sujet ici. La question est la suivante: Quel est le moyen préféré d’envoyer une URL à java?

Voici mon code actuel comme point de départ:

try {
    final URLConnection connection = new URL(url).openConnection();
    connection.connect();
    LOG.info("Service " + url + " available, yeah!");
    available = true;
} catch (final MalformedURLException e) {
    throw new IllegalStateException("Bad URL: " + url, e);
} catch (final IOException e) {
    LOG.info("Service " + url + " unavailable, oh no!", e);
    available = false;
}
  1. Est-ce que c'est bon du tout (ça va faire ce que je veux)?
  2. Dois-je en quelque sorte fermer la connexion?
  3. Je suppose que ceci est une requête GET. Existe-t-il un moyen d'envoyer HEAD à la place?
153
Sean Patrick Floyd

Est-ce que c'est bon du tout (ça va faire ce que je veux?)

Vous pouvez le faire Un autre moyen possible consiste à utiliser Java.net.Socket .

_public static boolean pingHost(String Host, int port, int timeout) {
    try (Socket socket = new Socket()) {
        socket.connect(new InetSocketAddress(Host, port), timeout);
        return true;
    } catch (IOException e) {
        return false; // Either timeout or unreachable or failed DNS lookup.
    }
}
_

Il y a aussi le InetAddress#isReachable() :

_boolean reachable = InetAddress.getByName(hostname).isReachable();
_

Toutefois, cela ne teste pas explicitement le port 80. Vous risquez d’obtenir de faux négatifs en raison d’un pare-feu bloquant d’autres ports.


Dois-je fermer la connexion?

Non, vous n'en avez pas explicitement besoin. Il est manipulé et mis en commun sous les capots.


Je suppose que c'est une demande GET. Existe-t-il un moyen d'envoyer HEAD à la place?

Vous pouvez convertir le URLConnection obtenu en HttpURLConnection puis utiliser setRequestMethod() pour définir la méthode de requête. Cependant, vous devez prendre en compte le fait que certaines applications Web médiocres ou des serveurs locaux peuvent renvoyer erreur HTTP 405 pour un HEAD (c'est-à-dire non disponible, non implémenté, non autorisé) alors qu'un GET fonctionne parfaitement bien. L'utilisation de GET est plus fiable si vous avez l'intention de vérifier les liens/ressources et non les domaines/hôtes.


Dans mon cas, le test de disponibilité du serveur n'est pas suffisant, je dois tester l'URL (la Webapp ne peut pas être déployée)

En effet, la connexion d'un hôte n'indique que si l'hôte est disponible, pas si le contenu est disponible. Il peut aussi bien arriver qu'un serveur Web ait démarré sans problème, mais la Webapp n'a pas pu être déployée lors du démarrage du serveur. Cependant, cela ne causera généralement pas la panne de tout le serveur. Vous pouvez déterminer cela en vérifiant si le code de réponse HTTP est 200.

_HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("HEAD");
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
    // Not OK.
}

// < 100 is undetermined.
// 1nn is informal (shouldn't happen on a GET/HEAD)
// 2nn is success
// 3nn is redirect
// 4nn is client error
// 5nn is server error
_

Pour plus de détails sur les codes d'état de réponse, voir RFC 2616 section 1 . L'appel de connect() n'est d'ailleurs pas nécessaire si vous déterminez les données de réponse. Il va implicitement se connecter.

Pour référence future, voici un exemple complet de la méthode d’utilité, prenant également en compte les délais d’expiration:

_/**
 * Pings a HTTP URL. This effectively sends a HEAD request and returns <code>true</code> if the response code is in 
 * the 200-399 range.
 * @param url The HTTP URL to be pinged.
 * @param timeout The timeout in millis for both the connection timeout and the response read timeout. Note that
 * the total timeout is effectively two times the given timeout.
 * @return <code>true</code> if the given HTTP URL has returned response code 200-399 on a HEAD request within the
 * given timeout, otherwise <code>false</code>.
 */
public static boolean pingURL(String url, int timeout) {
    url = url.replaceFirst("^https", "http"); // Otherwise an exception may be thrown on invalid SSL certificates.

    try {
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setConnectTimeout(timeout);
        connection.setReadTimeout(timeout);
        connection.setRequestMethod("HEAD");
        int responseCode = connection.getResponseCode();
        return (200 <= responseCode && responseCode <= 399);
    } catch (IOException exception) {
        return false;
    }
}
_
255
BalusC

Au lieu d'utiliser URLConnection, utilisez HttpURLConnection en appelant openConnection () sur votre objet URL.

Ensuite, utilisez getResponseCode () vous donnera la réponse HTTP une fois que vous avez lu la connexion.

voici le code:

    HttpURLConnection connection = null;
    try {
        URL u = new URL("http://www.google.com/");
        connection = (HttpURLConnection) u.openConnection();
        connection.setRequestMethod("HEAD");
        int code = connection.getResponseCode();
        System.out.println("" + code);
        // You can determine on HTTP return code received. 200 is success.
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }

Vérifiez également une question similaire Comment vérifier si une URL existe ou renvoie 404 avec Java?

J'espère que cela t'aides.

17
YoK

Vous pouvez également utiliser HttpURLConnection , ce qui vous permet de définir la méthode de requête (to HEAD par exemple). Voici un exemple qui montre comment envoyer une demande, lire la réponse et se déconnecter.

7
Bill the Lizard

Le code suivant effectue une demande HEAD pour vérifier si le site Web est disponible ou non.

public static boolean isReachable(String targetUrl) throws IOException
{
    HttpURLConnection httpUrlConnection = (HttpURLConnection) new URL(
            targetUrl).openConnection();
    httpUrlConnection.setRequestMethod("HEAD");

    try
    {
        int responseCode = httpUrlConnection.getResponseCode();

        return responseCode == HttpURLConnection.HTTP_OK;
    } catch (UnknownHostException noInternetConnection)
    {
        return false;
    }
}
4
BullyWiiPlaza

ici l'auteur suggère ceci:

public boolean isOnline() {
    Runtime runtime = Runtime.getRuntime();
    try {
        Process ipProcess = runtime.exec("/system/bin/ping -c 1 8.8.8.8");
        int     exitValue = ipProcess.waitFor();
        return (exitValue == 0);
    } catch (IOException | InterruptedException e) { e.printStackTrace(); }
    return false;
}

Questions possibles

  • Est-ce vraiment assez rapide? Oui, très vite!
  • Est-ce que je ne peux pas juste faire un ping sur ma propre page, que je veux quand même demander? Sûr! Vous pouvez même cocher les deux, si vous souhaitez faire la différence entre "connexion Internet disponible" et vos propres serveurs accessibles, et si le DNS est en panne? Google DNS (par exemple 8.8.8.8) est le plus grand service DNS public au monde. En 2013, il répond à 130 milliards de demandes par jour. Disons simplement que votre application ne répond pas ne serait probablement pas le sujet du jour.

lisez le lien. sa semble très bien

EDIT: dans mon exp de l'utiliser, ce n'est pas aussi rapide que cette méthode:

public boolean isOnline() {
    NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
    return netInfo != null && netInfo.isConnectedOrConnecting();
}

elles sont un peu différentes, mais dans la fonctionnalité de vérification de la connexion à Internet, la première méthode peut devenir lente en raison des variables de connexion.

3
Emad

Pensez à utiliser le framework Restlet, qui possède une excellente sémantique pour ce genre de choses. C'est puissant et flexible.

Le code pourrait être aussi simple que:

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
2
Avi Flax

wrt 2 .: vous feriez mieux de le fermer. Toutefois, cela peut dépendre de l'implémentation particulière d'URLConnection utilisée. Je viens juste de terminer la recherche d'une fuite de ressources dans notre système simplement à cause de cela. Une application a généré de nombreuses connexions suspendues (selon lsof; nous l’exécutons sous JDK 1.6) et la raison en était que nous avons utilisé exactement le morceau de code que vous avez montré. TCP Les connexions n'ont pas été fermées, par exemple. retournés à la piscine, etc. - ils ont été laissés dans l'état ESTABILISHED. Dans ce cas, le scénario approprié est celui présenté par YoK - transmettez-le à (HttpURLConnection) et appelez .disconnect ().

0
bartolomeo_n