วิธี Java ที่ต้องการเพื่อ ping HTTP URL สำหรับความพร้อมใช้งาน


157

ฉันต้องการคลาสการตรวจสอบที่ตรวจสอบอย่างสม่ำเสมอว่ามี URL HTTP ที่ให้บริการหรือไม่ ฉันสามารถดูแลส่วน "สม่ำเสมอ" โดยใช้ Spring TaskExecutor abstraction ดังนั้นนั่นไม่ใช่หัวข้อที่นี่ คำถามคือ: วิธีที่ดีที่สุดในการ ping URL ใน java คืออะไร?

นี่คือรหัสปัจจุบันของฉันเป็นจุดเริ่มต้น:

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แทนหรือไม่?

คำตอบ:


267

สิ่งนี้ดีหรือไม่ (จะทำในสิ่งที่ฉันต้องการหรือไม่)

คุณสามารถทำได้ 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()เพื่อตั้งค่าวิธีการร้องขอ อย่างไรก็ตามคุณต้องคำนึงถึงว่า webapps หรือเซิร์ฟเวอร์ homegrown บางตัวอาจส่งคืนข้อผิดพลาด HTTP 405สำหรับ HEAD (เช่นไม่พร้อมใช้งานไม่ได้ใช้ไม่ได้รับอนุญาต) ในขณะที่ GET ทำงานได้อย่างสมบูรณ์แบบ การใช้ GET มีความน่าเชื่อถือมากกว่าในกรณีที่คุณต้องการตรวจสอบลิงก์ / ทรัพยากรที่ไม่ใช่โดเมน / โฮสต์


การทดสอบเซิร์ฟเวอร์สำหรับความพร้อมใช้งานไม่เพียงพอในกรณีของฉันฉันต้องทดสอบ URL (อาจไม่สามารถปรับใช้ webapp)

แท้จริงแล้วการเชื่อมต่อโฮสต์จะแจ้งให้ทราบหากโฮสต์นั้นมีอยู่เท่านั้นหากเนื้อหานั้นพร้อมใช้งาน มันอาจเกิดขึ้นได้ดีที่เว็บเซิร์ฟเวอร์เริ่มขึ้นโดยไม่มีปัญหา แต่ webapp ล้มเหลวในการปรับใช้ระหว่างการเริ่มต้นของเซิร์ฟเวอร์ อย่างไรก็ตามจะไม่ทำให้เซิร์ฟเวอร์ทั้งหมดล่ม คุณสามารถตรวจสอบได้โดยตรวจสอบว่ารหัสตอบกลับ 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 มาตรา 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;
    }
}

3
ขอบคุณสำหรับรายละเอียดคำตอบเช่นนี้คือสิ่งที่ทำให้ SO เป็นสถานที่ที่ยอดเยี่ยม การทดสอบเซิร์ฟเวอร์สำหรับความพร้อมใช้งานนั้นไม่เพียงพอในกรณีของฉันฉันต้องทดสอบ URL (อาจไม่ได้ติดตั้งแอปพลิเคชันเว็บ) ดังนั้นฉันจะติดกับ HttpURLConnection เกี่ยวกับ HEAD ไม่ใช่การทดสอบที่ดี: เป็นวิธีที่ดีถ้าฉันรู้ว่า URL เป้าหมายรองรับ HEAD ฉันจะตรวจสอบดูว่า
ฌอนแพทริคฟลอยด์

1
เป็นไปได้ที่จะได้รับjava.io.IOException: จุดสิ้นสุดของสตรีมที่ไม่คาดคิดในบางเซิร์ฟเวอร์เพื่อแก้ไขคุณต้องเพิ่มการเชื่อมต่อ set.setRequestProperty เป็นที่ทราบกันดีว่าปัญหาและรายงานที่code.google.com
Marcin Waśniowski

1
@BalusC เพราะ (200 <= responseCode && responseCode <= 399) จะเป็นจริงถ้าหาก (การตอบสนอง <= 399) ซึ่งหมายความว่าเงื่อนไข (200 <= responseCode) ซ้ำซ้อน ดังนั้นฉันคิดว่ามันเป็นความผิดพลาด
metator

4
@metator: huh ??? มันไม่ซ้ำซ้อนอย่างแน่นอน รหัสการตอบสนองที่ต่ำกว่า 200 ถือว่าไม่ถูกต้อง
BalusC

1
@BalusC ฉันมีบางสถานการณ์ที่วิธีการเหล่านี้ดูเหมือนว่าใช้งานไม่ได้ดี ให้ดูที่นี่stackoverflow.com/questions/25805580/…
AndreaF

17

แทนที่จะใช้ URLConnection ให้ใช้HttpURLConnectionโดยการเรียก openConnection () บนวัตถุ URL ของคุณ

จากนั้นใช้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();
        }
    }

ตรวจสอบคำถามที่คล้ายกันวิธีตรวจสอบว่ามี URL อยู่หรือส่งคืน 404 ด้วย Java หรือไม่

หวังว่านี่จะช่วยได้



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

4

ที่นี่ผู้เขียนแนะนำสิ่งนี้:

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 ไม่ทำงาน Google DNS (เช่น 8.8.8.8) เป็นบริการ DNS สาธารณะที่ใหญ่ที่สุดในโลก ในปี 2013 มีการให้บริการ 130,000 คำขอต่อวัน สมมุติว่าแอปของคุณไม่ตอบสนองอาจไม่ใช่คำพูดประจำวัน

อ่านลิงค์ มันดูดีมาก

แก้ไข: ใน exp ของฉันใช้มันไม่เร็วเท่าวิธีนี้:

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

มันแตกต่างกันเล็กน้อย แต่ในฟังก์ชั่นสำหรับตรวจสอบการเชื่อมต่ออินเทอร์เน็ตวิธีแรกอาจช้าเนื่องจากตัวแปรการเชื่อมต่อ


2

พิจารณาใช้กรอบการทำงาน Restlet ซึ่งมีความหมายที่ดีสำหรับสิ่งนี้ มันทรงพลังและยืดหยุ่น

รหัสอาจเป็นเรื่องง่ายเหมือน:

Client client = new Client(Protocol.HTTP);
Response response = client.get(url);
if (response.getStatus().isError()) {
    // uh oh!
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.