Предпочтительный способ Java для отправки URL-адреса HTTP для доступности
Мне нужен класс монитора, который регулярно проверяет, доступен ли данный 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;
}
- Является ли это вообще хорошим (будет ли он делать то, что я хочу)?
- Должен ли я как-то закрыть соединение?
- Я предполагаю, что это запрос
GET
. Есть ли способ отправить HEAD
вместо этого?
Ответы
Ответ 1
Хорошо ли это вообще (будет ли он делать то, что я хочу?)
Вы можете сделать это. Другой возможный способ - использовать 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 error для HEAD (т.е. Недоступны, не реализованы, не допускается), а 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;
}
}
Ответ 2
Вместо использования 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?
Надеюсь, что это поможет.
Ответ 3
Вы также можете использовать HttpURLConnection, который позволяет вам установить метод запроса (например, для HEAD). Вот пример, который показывает, как отправить запрос, прочитать ответ и отключиться.
Ответ 4
Следующий код выполняет запрос 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;
}
}
Ответ 5
здесь автор предлагает следующее:
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 миллиардов запросов в день. Скажем так, ваше приложение не
ответ, вероятно, не будет разговором дня.
прочитайте ссылку. его кажется очень хорошим
EDIT:
в моем опыте использования, это не так быстро, как этот метод:
public boolean isOnline() {
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
return netInfo != null && netInfo.isConnectedOrConnecting();
}
они немного разные, но в функциональности только для проверки подключения к Интернету первый способ может стать медленным из-за переменных соединения.
Ответ 6
Рассмотрим использование среды Restlet, которая обладает большой семантикой для такого рода вещей. Он мощный и гибкий.
Код может быть таким же простым, как:
Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
// uh oh!
}
Ответ 7
wrt 2: вам лучше закрыть это. Однако это может зависеть от конкретной реализации URLConnection, которая используется. Я только что закончил отслеживать утечку ресурсов в нашей системе только из-за этого. Приложение создало множество висячих подключений (в соответствии с lsof, мы запускаем его на JDK1.6), и причина в том, что мы использовали именно тот фрагмент кода, который вы указали. Соединения TCP не были закрыты, например, вернулся в бассейн и т.д. - они остались в состоянии ESTABILISHED. В этом случае подходящим сценарием является тот, который показан YoK - передал его (HttpURLConnection) и вызывается .disconnect().