Forma Java preferida de contactar um URL de HTTP para a disponibilidade

preciso de uma classe de monitor que verifique regularmente se um dado URL HTTP está disponível. Eu posso cuidar da parte" regularmente " usando a abstração do executor de tarefas de primavera, então esse não é o tópico aqui. A questão é: Qual é a maneira preferida de ping uma URL em java?

Aqui está o meu código actual 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;
}
    Isto é bom de todo (fará o que eu quiser)? Tenho de fechar a ligação? Acho que sim. este é um pedido. Existe uma maneira de enviar HEAD em vez disso?
Author: blacktide, 2010-08-27

7 answers

isto é bom de todo (ele vai fazer o que eu quero?)

Podes fazê-lo. Outra maneira viável é usar 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, isto não testa explicitamente a porta 80. Corre-se o risco de obter falsos negativos devido a uma Firewall a bloquear outras portas.

tenho de fechar a ligação?

Não, Não precisas explicitamente. Está tratado e colocado debaixo dos capuzes.

suponho que seja um pedido de obtenção. Há uma maneira de enviar cabeça em vez disso?

Você pode lançar o obtido URLConnection para HttpURLConnection e depois usar setRequestMethod() para definir o método de pedido. No entanto, você precisa levar em conta que alguns webapps pobres ou servidores homegrown podem retornar HTTP 405 erro para um HEAD (ou seja, não disponível, Não implementado, não permitido) enquanto um GET funciona perfeitamente fino. Usar o GET é mais confiável no caso de você pretender verificar links/recursos não domínios/hosts.


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

De facto, ligar uma máquina só informa se a máquina está disponível, não se o conteúdo estiver disponível. Pode acontecer que um servidor web tenha começado sem problemas, mas o webapp não conseguiu implantar durante o início do servidor. Isto, no entanto, normalmente não fará com que o servidor inteiro para baixo. 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 mais pormenores sobre os códigos de estado da resposta, ver RFC 2616 secção 10 . Já agora, chamar connect() não é necessário para determinar os dados de resposta. Vai ligar-se implicitamente.

Para referência futura, aqui está um exemplo completo no sabor de um método de utilidade, também tendo em conta os tempos-limite:

/**
 * 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;
    }
}
 237
Author: BalusC, 2016-02-26 09:41:25

Em vez de usar o URLConnection use O HttpURLConnection invocando o openConnection() no seu objecto URL.

Então use getResponseCode () Dar-lhe-á a resposta HTTP assim que tiver lido a partir da ligaçã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 pergunta similar Como verificar se existe um URL ou devolve 404 com Java?

Espero que isto ajude.
 17
Author: YoK, 2017-05-23 12:34:38

Também pode utilizarHttpURLConnection , o que lhe permite definir o método de pedido (por exemplo, a cabeça). Aqui está um exemplo que mostra como enviar um pedido, ler a resposta e desligar.

 7
Author: Bill the Lizard, 2010-08-27 12:48:15

O seguinte código efectua um pedido HEAD para verificar se o sítio Web 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;
    }
}
 4
Author: BullyWiiPlaza, 2015-04-04 15:01:31

Aqui O escritor sugere isto:

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

Perguntas Possíveis

    Isto é suficientemente rápido?Sim, muito rápido! Não podia simplesmente ler a minha própria página, que eu quero para pedir de qualquer maneira? Claro! Até podes verificar os dois, se quiseres. diferenciar entre" Ligação à internet disponível " e a sua própria os servidores estão acessíveis e se o DNS estiver em baixo? Google DNS (e.g. 8.8.8.8) é o maior serviço público de DNS do mundo. = = ligações externas = = mil milhões de pedidos por dia. Vamos apenas dizer, a sua aplicação não responder provavelmente não seria a conversa do dia.

Lê a ligação. parece muito bom.

Editar: na minha exp de usá-lo, não é tão rápido como este método:

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

Eles são um pouco diferentes, mas na funcionalidade para apenas verificar a conexão à internet o primeiro método pode tornar-se lento devido às variáveis de conexão.

 3
Author: Emad, 2017-09-02 06:59:22

Considere usar a estrutura de Restlet, que tem grande semântica para este tipo de coisa. É poderoso e flexível.

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

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
 2
Author: Avi Flax, 2010-08-27 13:36:55

Wrt 2. é melhor fechares. No entanto, pode depender da implementação particular da ligação que é utilizada. Acabei de encontrar uma fuga de recursos no nosso sistema só por causa disso. Um aplicativo gerou muitas conexões de suspensão (de acordo com lsof; estamos executando-o em JDK1.6) e a razão foi que nós temos usado exatamente o pedaço de código que você mostrou. As conexões TCP não foram fechadas nem, por exemplo, retornadas ao pool, etc. - foram deixados em estado estável. Em neste caso, o cenário apropriado é aquele mostrado por YoK-cast para (HttpURLConnection) e invocar .desligar().

 0
Author: bartolomeo_n, 2013-01-19 12:40:06