1. ホーム
  2. java

[解決済み] HTTP URL に ping して可用性を確認するための望ましい Java の方法

2022-04-24 04:40:11

質問

与えられたHTTP URLが利用可能かどうかを定期的にチェックするモニタークラスが必要です。私は、Spring TaskExecutor抽象化を使用して、"regular"の部分の世話をすることができるので、それはここでのトピックではありません。問題は 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 の代わりに?

解決方法は?

<ブロッククオート

これで良いのだろうか(思い通りになるのだろうか)?

することができます。他の実現可能な方法としては 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を送信する方法はありますか?

をキャストすることができます。 URLConnection HttpURLConnection を使用し、その後に setRequestMethod() を使用して、リクエストメソッドを設定します。しかし、劣悪なウェブアプリケーションや自作サーバーの中には、リクエストメソッドに HTTP 405エラー の場合、GETは全く問題なく動作しますが、HEADの場合は(すなわち、利用できない、実装されていない、許可されていない)。ドメインやホストではなく、リンクやリソースを検証する場合は、GETを使用する方がより信頼性が高くなります。


<ブロッククオート

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

確かに、ホストに接続すると、ホストが利用可能かどうかが分かるだけで、コンテンツが利用可能かどうかは分かりません。ウェブサーバは問題なく起動したが、ウェブアプリケーションがサーバの起動中にデプロイに失敗した、ということもあり得ます。しかし、この場合、サーバー全体がダウンすることはありません。これは、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

レスポンスステータスコードの詳細については、以下を参照してください。 RFC2616第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;
    }
}