web-dev-qa-db-ja.com

優先度Java可用性のためにHTTP URLをpingする方法

特定のHTTP URLが利用可能かどうかを定期的にチェックするモニタークラスが必要です。 Spring TaskExecutor抽象化を使用して「定期的に」部品を処理できるので、ここでのトピックではありません。質問は次のとおりです。javaでURLをpingするのに望ましい方法は何ですか?

出発点としての現在のコードは次のとおりです。

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. これは何の役にも立ちませんか(私がしたいことをしますか)?
  2. どういうわけか接続を閉じる必要がありますか?
  3. これはGETリクエストだと思います。代わりにHEADを送信する方法はありますか?
151

これは何の役にも立ちません(私がやりたいことをするのでしょうか?)

あなたはそうすることができます。別の実行可能な方法は、 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.
    }
}

InetAddress#isReachable() もあります:

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

ただし、これはポート80を明示的にテストするものではありません。ファイアウォールが他のポートをブロックしているために、偽陰性になるリスクがあります。


どういうわけか接続を閉じる必要がありますか?

いいえ、明示的には必要ありません。フードの下で処理およびプールされます。


これはGETリクエストだと思います。代わりにHEADを送信する方法はありますか?

取得したURLConnectionHttpURLConnection にキャストしてから、 setRequestMethod() を使用して要求メソッドを設定できます。ただし、GETの実行中にHEADに対して HTTP 405エラー (つまり、利用できない、実装されていない、許可されていない)が返される可能性のある貧弱なWebアプリまたは自家製のサーバーを考慮する必要があります。完璧に動作します。ドメイン/ホストではなくリンク/リソースを検証する場合は、GETを使用する方が信頼性が高くなります。


私の場合、サーバーの可用性をテストするだけでは不十分です。URLをテストする必要があります(webappがデプロイされない場合があります)

実際、ホストを接続しても、ホストが利用可能かどうかだけが通知され、コンテンツが利用可能かどうかは通知されません。ウェブサーバーは問題なく起動したが、サーバーの起動中にwebappがデプロイに失敗したことはよく起こります。ただし、これにより通常、サーバー全体がダウンすることはありません。 HTTP応答コードが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

応答ステータスコードの詳細については、 RFC 2616セクション1 を参照してください。応答データを決定する場合、connect()の呼び出しは必要ありません。暗黙的に接続します。

将来の参考のために、ユーティリティメソッドのフレーバーの完全な例を示します。タイムアウトも考慮します。

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

URLConnectionを使用する代わりに、URLオブジェクトでopenConnection()を呼び出して HttpURLConnection を使用します。

次に、 getResponseCode() を使用して、接続から読み取った後、HTTP応答を提供します。

ここにコードがあります:

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

同様の質問も確認してください RLが存在するか、Javaで404を返すかどうかを確認する方法

お役に立てれば。

17
YoK

HttpURLConnection を使用することもできます。これにより、要求メソッドを設定できます(たとえば、HEADに)。 ここに例があります これは、リクエストの送信、レスポンスの読み取り、切断の方法を示しています。

7
Bill the Lizard

次のコードは、HEADリクエストを実行して、Webサイトが利用可能かどうかを確認します。

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

ここ 作家はこれを提案します:

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

考えられる質問

  • これは本当に十分に速いですか?はい、非常に速いです!
  • とにかくリクエストしたい自分のページにpingすることはできませんか?もちろん! 「インターネット接続が利用可能」か、自分のサーバーが到達可能かを区別したい場合は、両方をチェックすることもできます。DNSがダウンした場合はどうなりますか? Google DNS(例:8.8.8.8)は、世界最大のパブリックDNSサービスです。 2013年の時点で、1日に1,300億件のリクエストを処理しています。アプリが応答しないということは、おそらく今日の話ではないでしょう。

リンクを読んでください。それはとても良いようです

編集:それを使用する私の経験では、この方法ほど速くありません:

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

それらは少し異なりますが、インターネットへの接続を確認するだけの機能では、接続変数のために最初の方法が遅くなる場合があります。

3
Emad

Restletフレームワークの使用を検討してください。Restletフレームワークには、この種のことに対する優れたセマンティクスがあります。強力で柔軟です。

コードは次のように簡単です。

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

wrt 2 .:閉じてください。ただし、使用されるURLConnectionの特定の実装に依存する場合があります。その理由だけで、システムのリソースリークの追跡を終了しました。アプリは多くのハング接続を生成しました(lsofによると、JDK1.6で実行しています)。その理由は、示されているコードを正確に使用したためです。 TCP接続も閉じられませんでした。プールなどに戻されました-それらは確立された状態のままにされました。この場合、適切なシナリオは、YoKによって示されたシナリオです-(HttpURLConnection)にキャストし、.disconnect()を呼び出します。

0
bartolomeo_n