【问题标题】:Preferred Java way to ping an HTTP URL for availabilityping HTTP URL 以确保可用性的首选 Java 方法
【发布时间】:2011-04-04 19:04:39
【问题描述】:

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

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

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

【问题讨论】:

    标签: java http url ping


    【解决方案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() 设置请求方式。但是,您需要考虑到一些糟糕的 web 应用程序或本地服务器可能会为 HEAD 返回HTTP 405 error(即不可用、未实现、不允许),而 GET 工作得很好。如果您打算验证链接/资源而不是域/主机,则使用 GET 更可靠。


    在我的情况下测试服务器的可用性是不够的,我需要测试 URL(可能没有部署 webapp)

    确实,连接主机只通知主机是否可用,而不是内容是否可用。如果 web 服务器启动时没有问题,但 web 应用程序在服务器启动期间无法部署,这也是一件好事。然而,这通常不会导致整个服务器停机。您可以通过检查 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 section 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;
        }
    }
    

    【讨论】:

    • 感谢您提供详细信息,这样的答案使 SO 成为一个好地方。在我的情况下,测试服务器的可用性是不够的,我需要测试 URL(可能没有部署 webapp),所以我会坚持使用 HttpURLConnection。关于 HEAD 不是一个好测试:如果我知道目标 URL 支持 HEAD,这是一个好方法,我会检查一下。
    • 在某些服务器上可能会出现 java.io.IOException: unexpected end of stream,要修复它,您需要添加 connection.setRequestProperty("Accept-Encoding", “音乐匹配”);这是已知问题并在code.google.com 报告
    • @BalusC 因为 (200
    • @metator:嗯???这绝对不是多余的。低于 200 的响应代码被视为无效。
    • @BalusC 在某些情况下,这些方法似乎效果不佳。看看这里stackoverflow.com/questions/25805580/…
    【解决方案2】:

    通过在 URL 对象上调用 openConnection() 来代替使用 URLConnection 使用 HttpURLConnection

    然后使用 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();
            }
        }
    

    也检查类似的问题How to check if a URL exists or returns 404 with Java?

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      您也可以使用HttpURLConnection,它允许您设置请求方法(例如HEAD)。 Here's an example 展示了如何发送请求、读取响应和断开连接。

      【讨论】:

        【解决方案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;
          }
          

          可能的问题

          • 这真的够快吗?是的,非常快!
          • 我不能 ping 我自己的页面吗,我想要的 无论如何请求?当然!如果您愿意,您甚至可以同时检查两者 区分“可用的互联网连接”和您自己的 服务器可访问 如果 DNS 关闭了怎么办?谷歌 DNS(例如 8.8.8.8) 是世界上最大的公共 DNS 服务。截至 2013 年,它每天处理 1300 亿次请求。让我们说,你的应用程序不是 回应可能不是当时的话题。

          阅读链接。它看起来很不错

          编辑: 在我使用它的经验中,它没有这种方法快:

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

            【讨论】:

              猜你喜欢
              • 2013-05-03
              • 2011-11-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-10-30
              • 2012-02-18
              • 1970-01-01
              相关资源
              最近更新 更多