Cách Java ưa thích để ping URL HTTP có sẵn


157

Tôi cần một lớp màn hình thường xuyên kiểm tra xem một URL HTTP cụ thể có khả dụng hay không. Tôi có thể chăm sóc phần "thường xuyên" bằng cách sử dụng bản tóm tắt Spring TaskExecutor, vì vậy đó không phải là chủ đề ở đây. Câu hỏi là: cách ưa thích để ping URL trong java là gì?

Đây là mã hiện tại của tôi như là một điểm khởi đầu:

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. Điều này có tốt chút nào không (nó sẽ làm những gì tôi muốn)?
  2. Tôi có phải đóng kết nối bằng cách nào đó không?
  3. Tôi cho rằng đây là một GETyêu cầu. Có cách nào để gửi HEADthay thế?

Câu trả lời:


267

Điều này có tốt chút nào không (nó sẽ làm những gì tôi muốn chứ?)

Bạn có thể làm như vậy. Một cách khả thi khác là sử dụng 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.
    }
}

Ngoài ra còn có InetAddress#isReachable():

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

Tuy nhiên, điều này không kiểm tra rõ ràng cổng 80. Bạn có nguy cơ bị phủ định sai do Tường lửa chặn các cổng khác.


Tôi có phải đóng kết nối bằng cách nào đó không?

Không, bạn không cần rõ ràng. Nó được xử lý và gộp dưới mui xe.


Tôi cho rằng đây là một yêu cầu NHẬN. Có cách nào để gửi ĐẦU thay thế?

Bạn có thể truyền thu được URLConnectionđến HttpURLConnectionvà sau đó sử dụng setRequestMethod()để đặt phương thức yêu cầu. Tuy nhiên, bạn cần tính đến việc một số ứng dụng web hoặc máy chủ gia đình kém có thể trả về lỗi HTTP 405 cho một ĐẦU (nghĩa là không khả dụng, không được triển khai, không được phép) trong khi GET hoạt động hoàn toàn tốt. Sử dụng GET đáng tin cậy hơn trong trường hợp bạn có ý định xác minh các liên kết / tài nguyên không phải tên miền / máy chủ lưu trữ.


Kiểm tra tính khả dụng của máy chủ là không đủ trong trường hợp của tôi, tôi cần kiểm tra URL (ứng dụng web có thể không được triển khai)

Thật vậy, kết nối một máy chủ chỉ thông báo nếu máy chủ có sẵn, không phải nếu nội dung có sẵn. Điều tốt có thể xảy ra là một máy chủ web đã khởi động mà không gặp vấn đề gì, nhưng ứng dụng web không thể triển khai trong quá trình khởi động máy chủ. Tuy nhiên, điều này thường sẽ không làm cho toàn bộ máy chủ bị hỏng. Bạn có thể xác định rằng bằng cách kiểm tra xem mã phản hồi HTTP có phải là 200 không.

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

Để biết thêm chi tiết về mã trạng thái phản hồi, xem RFC 2616 phần 10 . Gọi connect()là bằng cách không cần thiết nếu bạn đang xác định dữ liệu phản hồi. Nó sẽ ngầm kết nối.

Để tham khảo trong tương lai, đây là một ví dụ hoàn chỉnh về hương vị của một phương thức tiện ích, cũng có tính đến thời gian chờ:

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

3
Cảm ơn các chi tiết, câu trả lời như thế này là những gì làm cho SO trở thành một nơi tuyệt vời. Kiểm tra tính khả dụng của máy chủ là không đủ trong trường hợp của tôi, tôi cần kiểm tra URL (ứng dụng web có thể không được triển khai), vì vậy tôi sẽ gắn bó với kết nối httpURLC. Về việc ĐẦU TIÊN không phải là một bài kiểm tra tốt: đó là một phương pháp tốt nếu tôi biết URL mục tiêu hỗ trợ CHÍNH, tôi sẽ kiểm tra xem.
Sean Patrick Floyd

1
Bạn có thể tải java.io.IOException: kết thúc luồng bất ngờ trên một số máy chủ, để khắc phục, bạn cần thêm Connection.setRequestProperty ("Chấp nhận mã hóa", "musixmatch"); Đó là sự cố đã biết và được báo cáo tại code.google.com
Marcin Waśniowski

1
@BalusC Bởi vì (200 <= answerCode && answerCode <= 399) sẽ đúng khi và chỉ khi (hồi đáp <= 399), có nghĩa là điều kiện (200 <= answerCode) là dự phòng. Vì vậy, tôi nghĩ rằng đó là một sai lầm.
metator

4
@metator: hả ??? Nó hoàn toàn không dư thừa. Mã phản hồi dưới 200 không được coi là hợp lệ.
BalusC

1
@BalusC Im một số tình huống phương pháp này dường như không hoạt động tốt. hãy xem tại đây stackoverflow.com/questions/25805580/
Mạnh

17

Thay vì sử dụng URLConnection, hãy sử dụng HTTPURLConnection bằng cách gọi openConnection () trên đối tượng URL của bạn.

Sau đó, sử dụng getResponseCode () sẽ cung cấp cho bạn phản hồi HTTP sau khi bạn đọc từ kết nối.

đây là mã:

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

Ngoài ra kiểm tra câu hỏi tương tự Làm thế nào để kiểm tra xem một URL có tồn tại hoặc trả về 404 với Java không?

Hi vọng điêu nay co ich.



4

Các mã sau đây thực hiện một HEADyêu cầu để kiểm tra xem trang web có sẵn hay không.

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

ở đây người viết gợi ý điều này:

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

Câu hỏi có thể

  • Điều này thực sự đủ nhanh? Có, rất nhanh!
  • Tôi không thể ping trang của riêng tôi, mà tôi muốn yêu cầu dù sao? Chắc chắn rồi! Thậm chí, bạn có thể kiểm tra cả hai, nếu bạn muốn phân biệt giữa kết nối internet có sẵn trên mạng và các máy chủ của riêng bạn có thể truy cập được Nếu DNS bị sập thì sao? Google DNS (ví dụ: 8.8.8.8) là dịch vụ DNS công cộng lớn nhất trên thế giới. Tính đến năm 2013, nó phục vụ 130 tỷ yêu cầu mỗi ngày. Hãy nói rằng, ứng dụng của bạn không phản hồi có thể sẽ không phải là cuộc nói chuyện trong ngày.

đọc liên kết. nó có vẻ rất tốt

EDIT: trong thời gian sử dụng của tôi, nó không nhanh như phương pháp này:

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

chúng hơi khác một chút nhưng trong chức năng chỉ kiểm tra kết nối với internet, phương thức đầu tiên có thể trở nên chậm do các biến kết nối.


2

Cân nhắc sử dụng khung Restlet, có ngữ nghĩa tuyệt vời cho loại điều này. Nó mạnh mẽ và linh hoạt.

Mã có thể đơn giản như:

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.