ping HTTP URL 以确保可用性的首选 Java 方式 [英] Preferred Java way to ping an HTTP URL for availability

查看:20
本文介绍了ping HTTP URL 以确保可用性的首选 Java 方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个监视器类来定期检查给定的 HTTP URL 是否可用.我可以使用 Spring TaskExecutor 抽象来处理定期"部分,所以这不是这里的主题.问题是:在 java 中 ping URL 的首选方法是什么?

I need a monitor class that regularly checks whether a given HTTP URL is available. I can take care of the "regularly" part using the Spring TaskExecutor abstraction, so that's not the topic here. The question is: What is the preferred way to ping a URL in java?

这是我当前的代码作为起点:

Here is my current code as a starting point:

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 ?
  1. Is this any good at all (will it do what I want)?
  2. Do I have to somehow close the connection?
  3. I suppose this is a GET request. Is there a way to send HEAD instead?

推荐答案

这有什么好处吗(它会做我想要的吗?)

你可以这样做.另一种可行的方法是使用 java.net.Socket.

You can do so. Another feasible way is using 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.由于防火墙阻止了其他端口,您可能会得到漏报.

This however doesn't explicitly test port 80. You risk to get false negatives due to a Firewall blocking other ports.

我必须以某种方式关闭连接吗?

不,您没有明确需要.它在引擎盖下处理和汇集.

No, you don't explicitly need. It's handled and pooled under the hoods.

我想这是一个 GET 请求.有没有办法改为发送 HEAD?

您可以将获得的 URLConnection 转换为 HttpURLConnection 然后使用 setRequestMethod() 设置请求方法.但是,您需要考虑到一些糟糕的 web 应用程序或本地服务器可能会返回 HTTP 405 错误(即不可用、未实现、不允许)而 GET 工作得很好.如果您打算验证链接/资源而不是域/主机,则使用 GET 更可靠.

You can cast the obtained URLConnection to HttpURLConnection and then use setRequestMethod() to set the request method. However, you need to take into account that some poor webapps or homegrown servers may return HTTP 405 error for a HEAD (i.e. not available, not implemented, not allowed) while a GET works perfectly fine. Using GET is more reliable in case you intend to verify links/resources not domains/hosts.

在我的情况下测试服务器的可用性是不够的,我需要测试 URL(可能未部署 web 应用程序)

实际上,连接主机只会通知主机是否可用,而不是内容是否可用.Web 服务器启动时没有问题,但 Web 应用程序在服务器启动期间未能部署,这也可能发生.然而,这通常不会导致整个服务器宕机.您可以通过检查 HTTP 响应代码是否为 200 来确定.

Indeed, connecting a host only informs if the host is available, not if the content is available. It can as good happen that a webserver has started without problems, but the webapp failed to deploy during server's start. This will however usually not cause the entire server to go down. You can determine that by checking if the HTTP response code is 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().它将隐式连接.

For more detail about response status codes see RFC 2616 section 10. Calling connect() is by the way not needed if you're determining the response data. It will implicitly connect.

为了将来参考,这里有一个实用方法风格的完整示例,还考虑了超时:

For future reference, here's a complete example in flavor of an utility method, also taking account with timeouts:

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

这篇关于ping HTTP URL 以确保可用性的首选 Java 方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆