可用性のためにHTTP URLにpingするための推奨Java方法


157

特定の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代わりに送信する方法はありますか?

回答:


267

これは何か良いことですか(私がやりたいことをしますか?)

あなたはそうすることができます。別の実行可能な方法は、を使用すること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が完全に正常に機能する一方で、一部の貧弱なWebアプリケーションまたは自社開発サーバーがHEADに対してHTTP 405エラー(つまり、使用不可、実装されていない、許可されていない)を返す可能性があることを考慮する必要があります。ドメイン/ホストではなくリンク/リソースを検証する場合は、GETを使用する方が信頼性が高くなります。


私の場合、サーバーの可用性をテストするだけでは十分ではありません。URLをテストする必要があります(Webアプリケーションがデプロイされていない可能性があります)

実際、ホストを接続すると、ホストが利用可能かどうかが通知されるだけで、コンテンツが利用可能かどうかは通知されません。Webサーバーが問題なく起動したのに、サーバーの起動中にWebアプリケーションが展開に失敗したこともよくあります。ただし、これによってサーバー全体がダウンすることは通常ありません。これは、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セクション10を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;
    }
}

3
詳細をお寄せいただきありがとうございます。このような回答がSOを素晴らしい場所にしています。私の場合、サーバーの可用性をテストするだけでは十分ではありません。URLをテストする必要があるため(webappがデプロイされていない可能性があります)、HttpURLConnectionを使用します。HEADが適切なテストではないことについて:ターゲットURLがHEADをサポートしていることがわかっている場合は、これを確認します。
ショーンパトリックフロイド

1
一部のサーバーではjava.io.IOException:予期しないストリームの終わりを取得する可能性があります。これを修正するには、connection.setRequestProperty( "Accept-Encoding"、 "musixmatch");を追加する必要があります。それはで報告された問題と知られていますcode.google.com
マルチンWaśniowski

1
@BalusC(200 <= responseCode && responseCode <= 399)は、(response <= 399)の場合にのみtrueになるため、(200 <= responseCode)条件は冗長です。だから間違いだと思った。
メタター

4
@metator:ハァッ??? まったく冗長ではありません。200未満の応答コードは有効とは見なされません。
BalusC 2014

1
@BalusCいくつかの状況では、これらの方法はうまく機能しないようです。ここ外観を与えるstackoverflow.com/questions/25805580/...
AndreaF

17

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

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

お役に立てれば。



4

次のコードは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

ここで作家はこれを示唆しています:

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

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


2

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

コードは次のように単純にすることができます。

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.