2010-08-27 23 views
126

我需要一個監視器類,定期檢查給定的HTTP URL是否可用。我可以使用Spring TaskExecutor抽象來關心「常規」部分,所以這不是這裏的主題。問題是:什麼是在Java中ping URL的首選方法?首選的Java方法來ping HTTP 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而不是?

回答

215

這是任何好處都沒有(將它做我想要什麼?)

你可以這樣做。另一種可行的方法是使用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呢?

可以澆鑄獲得的URLConnectionHttpURLConnection然後使用setRequestMethod()設置請求方法。但是,您需要考慮到一些糟糕的webapps或本地服務器可能會返回HTTP 405 error作爲HEAD(即不可用,未實現,不允許),而GET工作得很好。如果您打算驗證鏈接/資源而不是域/主機,則使用GET更可靠。


測試可用性的服務器是不夠的,在我的情況,我需要測試的URL(web應用程序可能不會部署)

事實上,連接主機僅通告如果主機可用,則不是如果內容可用。 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; 
    } 
} 
+2

感謝您的詳細信息,這樣的答案是什麼讓SO成爲一個好地方。在我的情況下測試服務器的可用性是不夠的,我需要測試URL(可能不會部署webapp),所以我會堅持使用HttpURLConnection。關於HEAD不是一個好的測試:如果我知道目標URL支持HEAD,這是一個好方法,我會檢查它。 – 2010-08-27 13:09:06

+0

如果這是功能要求,那麼'HttpURLConnection'是最好的方法。你也想確定響應代碼。你也可以使用'Socket'來做到這一點,但這隻會增加冗長並需要有關HTTP規範的知識。 – BalusC 2010-08-27 13:26:56

+1

有可能獲得** java.io.IOException:在某些服務器上發生意外的流**結束,要修復它,您需要添加connection.setRequestProperty(「Accept-Encoding」, 「musixmatch」); 這是已知問題,並在[code.google.com](https://code.google.com/p/android/issues/detail?id=24672) – 2013-03-27 09:06:31

16

而不是使用的URLConnection通過您的網址對象調用的openConnection()使用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?

希望這有助於。

1

考慮使用Restlet框架,它具有很好的語義。它強大而靈活。

的代碼可能是簡單的:

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

WRT 2:你最好做關閉它。但是,它可能取決於所使用的URLConnection的特定實現。我剛剛完成追蹤我們系統中的資源泄漏。一個應用程序生成了很多掛起的連接(根據lsof;我們在JDK1.6上運行它),原因是我們已經使用了您顯示的代碼片段。 TCP連接並未關閉,例如回到泳池等等 - 他們被留在ESTABILISHED狀態。在這種情況下,適當的場景是YoK顯示的場景 - 將其轉換爲(HttpURLConnection)並調用.disconnect()。

+0

這應該是一個評論,而不是一個答案。考慮通過對相關答案或問題本身進行評論來發現您發現的內容。 – Khez 2013-01-19 13:05:15

+0

您的問題是您從未關閉過輸入流。調用'disconnect()'可以防止發生連接池,這在一般情況下是不可取的。 – EJP 2016-06-09 23:21:06

2

以下代碼執行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; 
    } 
} 
2

here筆者提出這樣的:

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我自己的頁面,我想 要求嗎?當然!你甚至可以檢查兩者,如果你想 區分「可用的互聯網連接」和你自己的 服務器beeing可達如果DNS關閉? Google DNS(例如 8.8.8.8)是全球最大的公共DNS服務。截至2013年,它每天提供1300億個請求。我們只是說,你的應用程序不是 的迴應可能不是當天的談話。

閱讀鏈接。它看起來很不錯

編輯:我在使用它的EXP ,它的速度比不上這個方法:

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

他們有點不同,但在功能只是檢查互聯網的連接由於連接變量,第一種方法可能會變慢。