Мне нужен класс монитора, который регулярно проверяет, доступен ли данный HTTP-URL. Я могу позаботиться о «регулярной» части, используя абстракцию 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
? Хорошо ли это вообще (будет ли это делать то, что я хочу?)
Вы можете сделать это. Другой возможный способ — использовать java.net.Розетка
.
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 для 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;
}
}
Рассмотрите возможность использования инфраструктуры Restlet, которая имеет отличную семантику для такого рода вещей. Он мощный и гибкий.
Код может быть таким простым, как:
Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
// uh oh!
}
Вместо использования 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?
Надеюсь, это поможет.