Предпочтительный способ Java для проверки доступности HTTP-URL


мне нужен класс монитора, который регулярно проверяет, доступен ли данный URL-адрес HTTP. Я могу позаботиться о" регулярной " части, используя абстракцию Spring TaskExecutor, так что это не тема здесь. Вопрос в том:каков предпочтительный способ пинга URL-адреса в java?

вот мой текущий код в качестве отправной точки:

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 вместо?
7 138

7 ответов:

это вообще хорошо (будет ли он делать то, что я хочу?)

вы можете это сделать. Другим возможным способом является использование 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. Есть ли способ отправить голову вместо этого?

вы можете бросить полученный URLConnection до HttpURLConnection и затем использовать setRequestMethod() для установки метода запроса. Однако вы должны учитывать, что некоторые плохие веб-приложения или доморощенные серверы могут возвратить ошибка HTTP 405 для головы (т. е. недоступно, не реализовано, не разрешено), в то время как GET работает отлично. Использование 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

для получения более подробной информации о кодах состояния ответа см. 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;
    }
}

вместо использования URLConnection используйте HttpURLConnection вызывая openConnection () на вашем объекте URL.

затем использовать 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();
        }
    }

также проверьте аналогичный вопрос Как проверить, если URL существует или возвращает 404 с Java?

надеюсь, что это помогает.

вы также можете использовать HttpURLConnection, что позволяет установить метод запроса (например, HEAD). вот пример это показывает, как отправить запрос, прочитать ответ и отключить.

следующий код выполняет HEAD запрос на проверку доступности веб-сайта.

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

здесь автор предлагает следующее:

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

Возможные Вопросы

  • это действительно достаточно быстро?Да, очень быстро!
  • не мог бы я просто пинговать свою собственную страницу, которую я хочу чтобы запросить в любом случае? Конечно! Вы даже можете проверить оба, если хотите различайте "доступное подключение к интернету" и свое собственное серверы становятся доступными что делать, если DNS не работает? Google DNS (например 8.8.8.8) является крупнейшим публичным DNS-сервисом в мире. Как в 2013 году он обслуживает 130 миллиардов запросов в день. Давайте просто скажем, что ваше приложение нет ответ, вероятно, не был бы разговором дня.

читать по ссылке. это кажется очень хорошим

изменить: в моего опыта его использования, это не так быстро, как этот метод:

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

они немного отличаются, но в функциональности для просто проверки подключения к интернету первый метод может стать медленным из-за переменных подключения.

рассмотрите возможность использования фреймворка Restlet, который имеет большую семантику для такого рода вещей. Он мощный и гибкий.

код может быть таким же простым, как:

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

wrt 2.- тебе лучше закрыть его. Однако, это может зависеть от конкретной реализации URLConnection, который используется. Я только что закончил отслеживать утечки ресурсов в нашей системе только из-за этого. Приложение сгенерировало множество висячих соединений (согласно lsof; мы запускаем его на JDK1.6), и причина в том, что мы использовали именно тот фрагмент кода, который вы показали. TCP-соединения не были закрыты, например, возвращены в пул и т. д. - они были оставлены в стабильном состоянии. В в этом случае правильный сценарий-это тот, который показан YoK-cast it to (HttpURLConnection) и invoke .разъединять.)(