it-swarm.com.de

Bevorzugte Java Möglichkeit, eine HTTP-URL für die Verfügbarkeit zu pingen

Ich benötige eine Monitorklasse, die regelmäßig überprüft, ob eine bestimmte HTTP-URL verfügbar ist. Ich kann mich mit der Spring TaskExecutor-Abstraktion um den "regulären" Teil kümmern, daher ist das hier nicht das Thema. Die Frage ist: Was ist der bevorzugte Weg, um eine URL in Java zu pingen?

Hier ist mein aktueller Code als Ausgangspunkt:

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. Ist das überhaupt gut (wird es tun, was ich will)?
  2. Muss ich die Verbindung irgendwie trennen?
  3. Ich nehme an, dies ist eine GET Anfrage. Gibt es eine Möglichkeit, stattdessen HEAD zu senden?
153

Ist das überhaupt gut (wird es tun, was ich will?)

Sie können das tun. Ein anderer möglicher Weg ist die Verwendung von 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.
    }
}

Es gibt auch die InetAddress#isReachable() :

boolean reachable = InetAddress.getByName(hostname).isReachable();

Hiermit wird Port 80 jedoch nicht explizit getestet. Es besteht die Gefahr, dass durch eine Firewall, die andere Ports blockiert, falsche Negative angezeigt werden.


Muss ich die Verbindung irgendwie trennen?

Nein, das brauchst du nicht explizit. Es wird unter den Hauben gehandhabt und gepoolt.


Ich nehme an, das ist eine GET-Anfrage. Gibt es eine Möglichkeit, HEAD stattdessen zu senden?

Sie können das erhaltene URLConnection in HttpURLConnection umwandeln und dann setRequestMethod() verwenden, um die Anforderungsmethode festzulegen. Sie müssen jedoch berücksichtigen, dass einige schlechte Webanwendungen oder selbst erstellte Server möglicherweise HTTP 405-Fehler für a HEAD (dh nicht verfügbar, nicht implementiert, nicht zulässig) zurückgeben. Während ein GET einwandfrei funktioniert, ist die Verwendung von GET zuverlässiger, wenn Sie Links/Ressourcen, nicht Domänen/Hosts, überprüfen möchten.


Das Testen der Verfügbarkeit des Servers ist in meinem Fall nicht ausreichend. Ich muss die URL testen (die Webanwendung wird möglicherweise nicht bereitgestellt).

Wenn Sie einen Host verbinden, wird nur angezeigt, ob der Host verfügbar ist, nicht, ob der Inhalt verfügbar ist. Es kann durchaus vorkommen, dass ein Webserver ohne Probleme gestartet wurde, die Webanwendung jedoch beim Serverstart nicht bereitgestellt werden konnte. Dies führt jedoch normalerweise nicht zum Ausfall des gesamten Servers. Sie können dies feststellen, indem Sie prüfen, ob der HTTP-Antwortcode 200 lautet.

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

Weitere Informationen zu Antwortstatuscodes finden Sie unter RFC 2616, Abschnitt 1 . Der Aufruf von connect() wird übrigens nicht benötigt, um die Antwortdaten zu ermitteln. Es wird implizit eine Verbindung hergestellt.

Zur späteren Bezugnahme hier ein vollständiges Beispiel für eine Utility-Methode, das auch Zeitüberschreitungen berücksichtigt:

/**
 * 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

Verwenden Sie statt URLConnection HttpURLConnection , indem Sie openConnection () für Ihr URL-Objekt aufrufen.

Verwenden Sie dann getResponseCode () , um die HTTP-Antwort zu erhalten, sobald Sie die Verbindung gelesen haben.

hier ist 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();
        }
    }

Überprüfen Sie auch ähnliche Fragen Wie kann man mit Java überprüfen, ob eine URL existiert oder 404 zurückgibt?

Hoffe das hilft.

17
YoK

Sie können auch HttpURLConnection verwenden, um die Anforderungsmethode festzulegen (auf HEAD zum Beispiel). Hier ist ein Beispiel das zeigt, wie Um eine Anfrage zu senden, lesen Sie die Antwort und trennen Sie die Verbindung.

7
Bill the Lizard

Der folgende Code führt eine HEAD -Anforderung aus, um zu überprüfen, ob die Website verfügbar ist oder nicht.

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

hier der Schreiber schlägt vor:

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;
}

Mögliche Fragen

  • Ist das wirklich schnell genug? Ja, sehr schnell!
  • Könnte ich nicht einfach meine eigene Seite anpingen, die ich trotzdem anfordern möchte? Sicher! Sie können sogar beides überprüfen, wenn Sie zwischen "Internetverbindung verfügbar" und erreichbaren eigenen Servern unterscheiden möchten. Was ist, wenn der DNS nicht verfügbar ist? Google DNS (z. B. 8.8.8.8) ist der weltweit größte öffentliche DNS-Dienst. Ab 2013 werden 130 Milliarden Anfragen pro Tag bearbeitet. Sagen wir einfach, Ihre App, die nicht reagiert, ist wahrscheinlich nicht das Thema des Tages.

lesen Sie den Link. es scheint sehr gut zu sein

BEARBEITEN: in meiner exp es zu verwenden, ist es nicht so schnell wie diese Methode:

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

sie sind ein bisschen anders, aber in der Funktionalität, nur die Verbindung zum Internet zu überprüfen, kann die erste Methode aufgrund der Verbindungsvariablen langsam werden.

3
Emad

Ziehen Sie die Verwendung des Restlet-Frameworks in Betracht, das eine hervorragende Semantik für diese Art von Dingen bietet. Es ist leistungsstark und flexibel.

Der Code könnte so einfach sein wie:

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

zu 2 .: Schließen Sie es besser. Dies kann jedoch von der speziellen Implementierung von URLConnection abhängen, die verwendet wird. Ich habe gerade ein Ressourcenleck in unserem System aus diesem Grund aufgespürt. Eine App erzeugte viele hängende Verbindungen (laut lsof; wir verwenden sie auf JDK1.6) und der Grund dafür war, dass wir genau den Code verwendet haben, den Sie gezeigt haben. TCP Verbindungen wurden weder geschlossen noch zB in den Pool zurückgeschickt usw. - sie wurden im Zustand ESTABILISHED belassen. In diesem Fall ist das von YoK gezeigte Szenario das richtige - wandle es in (HttpURLConnection) und Rufen Sie .disconnect () auf.

0
bartolomeo_n