Maneira Java preferencial de fazer ping de um URL HTTP para disponibilidade

Eu preciso de uma class de monitor que verifique regularmente se um determinado URL HTTP está disponível. Eu posso cuidar da parte “regularmente” usando a abstração Spring TaskExecutor, então esse não é o tópico aqui. A pergunta é: qual é a maneira preferida de fazer ping de uma URL em java?

Aqui está o meu código atual como ponto de partida:

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. Isso é bom de algum modo (fará o que eu quiser)?
  2. Eu tenho que de alguma forma fechar a conexão?
  3. Eu suponho que este é um pedido GET . Existe uma maneira de enviar HEAD vez disso?

Isso é bom de algum modo? (Fará o que eu quiser?)

Você pode fazer isso. Outra maneira viável é usar o 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. } } 

Há também o InetAddress#isReachable() :

 boolean reachable = InetAddress.getByName(hostname).isReachable(); 

No entanto, isso não testa explicitamente a porta 80. Você corre o risco de obter falsos negativos devido a um Firewall bloqueando outras portas.


Eu tenho que de alguma forma fechar a conexão?

Não, você não precisa explicitamente. É manuseado e agrupado sob os capôs.


Eu suponho que este é um pedido GET. Existe uma maneira de enviar HEAD em vez disso?

Você pode converter a URLConnection obtida em HttpURLConnection e, em seguida, usar setRequestMethod() para definir o método de solicitação. No entanto, é preciso levar em conta que alguns aplicativos Web ou servidores domésticos mal-intencionados podem retornar um erro HTTP 405 para um HEAD (ou seja, não disponível, não implementado, não permitido) enquanto um GET funciona perfeitamente. O uso de GET é mais confiável caso você pretenda verificar links / resources e não domínios / hosts.


Testando o servidor para disponibilidade não é suficiente no meu caso, eu preciso testar o URL (o webapp não pode ser implantado)

De fato, conectar um host apenas informa se o host está disponível, não se o conteúdo estiver disponível. Pode acontecer que um servidor da Web tenha iniciado sem problemas, mas o webapp não pôde ser implementado durante o início do servidor. Isso normalmente não fará com que todo o servidor fique inativo. Você pode determinar isso verificando se o código de resposta 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 

Para obter mais detalhes sobre códigos de status de resposta, consulte a seção 10 da RFC 2616 . Chamar connect() não é necessário se você estiver determinando os dados de resposta. Ela se conectará implicitamente.

Para referência futura, aqui está um exemplo completo do sabor de um método utilitário, considerando também os tempos limite:

 /** * Pings a HTTP URL. This effectively sends a HEAD request and returns true 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 true if the given HTTP URL has returned response code 200-399 on a HEAD request within the * given timeout, otherwise false. */ 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; } } 

Em vez de usar URLConnection, use HttpURLConnection chamando openConnection () em seu object URL.

Em seguida, use getResponseCode () para obter a resposta HTTP depois de ler a conexão.

aqui está o código:

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

Verifique também a questão semelhante Como verificar se existe um URL ou devolve 404 com Java?

Espero que isto ajude.

Você também pode usar HttpURLConnection , que permite definir o método de solicitação (para HEAD, por exemplo). Veja um exemplo que mostra como enviar uma solicitação, ler a resposta e desconectar.

O código a seguir executa uma solicitação HEAD para verificar se o site está disponível ou não.

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

aqui o escritor sugere isso:

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

Possíveis perguntas

  • Isso é realmente rápido o suficiente? Sim, muito rápido!
  • Eu não poderia simplesmente fazer o ping na minha própria página, o que eu quero solicitar de qualquer maneira? Certo! Você poderia até mesmo verificar ambos, se quiser diferenciar entre “conexão de internet disponível” e seus próprios servidores sendo alcançados. E se o DNS estiver inativo? O DNS do Google (por exemplo, 8.8.8.8) é o maior serviço de DNS público do mundo. A partir de 2013, atende 130 bilhões de pedidos por dia. Digamos que seu aplicativo não está respondendo provavelmente não seria a conversa do dia.

leia o link. parece muito bom

EDIT: no meu exp de usá-lo, não é tão rápido quanto este método:

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

eles são um pouco diferentes, mas na funcionalidade de apenas verificar a conexão com a Internet, o primeiro método pode se tornar lento devido às variables ​​de conexão.

Considere o uso do framework Restlet, que possui uma grande semântica para esse tipo de coisa. É poderoso e flexível.

O código pode ser tão simples quanto:

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

wrt 2 .: é melhor você fechar. No entanto, isso pode depender da implementação particular de URLConnection que é usada. Eu acabei de rastrear um vazamento de resources em nosso sistema apenas por causa disso. Um aplicativo gerou muitas conexões suspensas (de acordo com o lsof; estamos executando no JDK1.6) e o motivo foi que usamos exatamente o código que você mostrou. Conexões TCP não foram fechadas nem, por exemplo, retornou ao pool, etc – eles foram deixados no estado ESTABILIZADO. Nesse caso, o cenário apropriado é aquele mostrado pelo YoK – converta para (HttpURLConnection) e invoque .disconnect ().