Kullanılabilirlik için bir HTTP URL'sine ping atmanın tercih edilen Java yolu


158

Belirli bir HTTP URL kullanılabilir olup olmadığını düzenli olarak kontrol eden bir monitör sınıfına ihtiyacım var. Ben Spring TaskExecutor soyutlama kullanarak "düzenli" kısmı ilgilenebilir, bu yüzden burada konu değil. Soru şu: Java'da bir URL'ye ping atmanın tercih edilen yolu nedir?

İşte benim başlangıç ​​kodu olarak benim geçerli kod:

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. Bu hiç iyi mi (istediğimi yapacak mı?)
  2. Bağlantıyı bir şekilde kapatmak zorunda mıyım?
  3. Sanırım bu bir GETistek. HEADBunun yerine göndermenin bir yolu var mı ?

Yanıtlar:


267

Bu hiç iyi mi (istediğimi yapacak mı?)

Bunu yapabilirsiniz. Başka bir uygun yol da kullanmaktır 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.
    }
}

Ayrıca InetAddress#isReachable():

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

Ancak bu bağlantı noktası 80'i açıkça test etmez. Güvenlik Duvarı'nın diğer bağlantı noktalarını engellediği için yanlış negatif alma riskiniz vardır.


Bağlantıyı bir şekilde kapatmak zorunda mıyım?

Hayır, açıkça ihtiyacınız yok. Davlumbazların altında tutulur ve havuzlanır.


Sanırım bu bir GET isteğidir. Bunun yerine HEAD göndermenin bir yolu var mı?

Sen elde yayınlayabileceğim URLConnectioniçin HttpURLConnectionve daha sonra kullanmak setRequestMethod()istek yöntemini ayarlayın. Bununla birlikte, bazı zayıf webapps'ların veya ev sahibi sunucuların bir HEAD için HTTP 405 hatası döndürebileceğini (yani mevcut değil, uygulanmadı, izin verilmez) göz önünde bulundurmanız gerekir . Etki alanlarını / ana bilgisayarları değil bağlantıları / kaynakları doğrulamak istediğinizde GET kullanmak daha güvenilirdir.


Sunucumu kullanılabilirlik açısından test etmek benim durumumda yeterli değil, URL'yi test etmem gerekiyor (web uygulaması dağıtılamayabilir)

Gerçekten de, bir ana makineye bağlanmak, içeriğin kullanılabilir olup olmadığını değil, yalnızca ana makinenin kullanılabilir olup olmadığını bildirir. Bir web sunucusunun sorunsuz başlamış olması da mümkündür, ancak webapp sunucunun başlaması sırasında konuşlandırılamadı. Ancak bu genellikle tüm sunucunun çökmesine neden olmaz. HTTP yanıt kodunun 200 olup olmadığını kontrol ederek bunu belirleyebilirsiniz.

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

Yanıt durum kodları hakkında daha fazla bilgi için bkz. RFC 2616 bölüm 10 . connect()Yanıt verilerini belirlerseniz, arama yapılması gerekmez. Örtük olarak bağlanacaktır.

Gelecekte başvurmak için, zaman aşımlarını da dikkate alarak bir yardımcı program yönteminin lezzetinde tam bir örnek:

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

3
Ayrıntılar için teşekkürler, SO gibi harika bir yer yapan bu gibi cevaplar. Sunucumu kullanılabilirlik için test etmek benim durumumda yeterli değil, ben URL (webapp konuşlandırılmamış olabilir) test etmek gerekir, bu yüzden HttpURLConnection ile sopa olacak. HEAD'in iyi bir test olmaması hakkında: Hedef URL'nin HEAD'i desteklediğini biliyorsanız iyi bir yöntemdir, bunu kontrol edeceğim.
Sean Patrick Floyd

1
Java.io.IOException: bazı sunucularda beklenmeyen akış sonu almak mümkündür , düzeltmek için connection.setRequestProperty ("Accept-Encoding", "musixmatch") eklemeniz gerekir; Bilinen bir sorun ve code.google.com
Marcin Waśniowski

1
@BalusC Çünkü (200 <= responseCode && responseCode <= 399) yalnızca ve yalnızca (yanıt <= 399) ise doğru olacaktır, yani (200 <= responseCode) koşulu gereksiz demektir. Bu yüzden bir hata olduğunu düşündüm.
metator

4
@metator: ha ??? Kesinlikle gereksiz değildir. 200'den düşük yanıt kodları geçerli sayılmaz.
BalusC

1
@BalusC Im bazı durumlarda bu yöntem iyi çalışmıyor gibi görünüyor. buraya bir göz atın stackoverflow.com/questions/25805580/…
AndreaF

17

Bunun yerine URLConnection kullanımını kullanmanın HttpURLConnection URL nesne üzerinde OpenConnection () arayarak.

Ardından getResponseCode () yöntemini kullanın , bağlantıdan okuduğunuzda size HTTP yanıtı verilir.

İşte kod:

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

Benzer soruyu da kontrol et kontrol edin Bir URL'nin var olup olmadığını veya Java ile 404 döndürüp döndürmediğini nasıl kontrol edebilirim?

Bu yardımcı olur umarım.



4

Aşağıdaki kod HEAD, web sitesinin kullanılabilir olup olmadığını kontrol etmek için bir istekte bulunur.

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

burada yazar şunu önerir:

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

Olası Sorular

  • Bu gerçekten yeterince hızlı mı? Evet, çok hızlı!
  • Zaten talep etmek istediğim kendi sayfama ping atamaz mıydım? Elbette! "İnternet bağlantısı mevcut" ile kendi sunucularınız arasında ayrım yapmak istiyorsanız her ikisini de kontrol edebilirsiniz. DNS çalışmıyorsa ne olur? Google DNS (ör. 8.8.8.8), dünyanın en büyük genel DNS hizmetidir. 2013 yılı itibariyle günde 130 milyar talebe hizmet etmektedir. Sadece diyelim ki yanıt vermeyen uygulamanız muhtemelen günün konuşması olmaz.

bağlantıyı okuyun. çok iyi görünüyor

EDIT: benim exp kullanarak, bu yöntem kadar hızlı değil:

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

onlar biraz farklı ama sadece internet bağlantısı kontrol işlevselliği bağlantı değişkenleri nedeniyle ilk yöntem yavaş olabilir.


2

Bu tür şeyler için harika semantiğe sahip Restlet çerçevesini kullanmayı düşünün. Güçlü ve esnektir.

Kod şu kadar basit olabilir:

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.