가용성을 위해 HTTP URL을 핑하는 기본 Java 방법


157

주어진 HTTP URL이 사용 가능한지 정기적으로 확인하는 모니터 클래스가 필요합니다. Spring TaskExecutor 추상화를 사용하여 "일반적으로"부분을 처리 할 수 ​​있으므로 여기서는 주제가 아닙니다. 문제는 다음과 같습니다. java에서 URL을 ping하는 기본 방법은 무엇입니까?

다음은 현재 코드입니다.

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()요청 방법을 설정하는 데 사용할 수 있습니다 . 그러나 GET이 완벽하게 작동하는 동안 일부 불량 웹 응용 프로그램 또는 자체 개발 서버 에서 HEAD에 대해 HTTP 405 오류 (즉, 사용할 수 없거나 구현되지 않았으며 허용되지 않음)를 반환 할 수 있다는 점을 고려해야 합니다. 도메인 / 호스트가 아닌 링크 / 리소스를 확인하려는 경우 GET을 사용하는 것이 더 안정적입니다.


내 경우 서버의 가용성 테스트가 충분하지 않습니다 .URL을 테스트해야합니다 (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을 테스트해야합니다 (webapp가 배포되지 않았을 수 있음) .HttpURLConnection을 사용합니다. HEAD가 좋지 않은 테스트 정보 : 대상 URL이 HEAD를 지원한다는 것을 알면 좋은 방법입니다.
Sean Patrick Floyd

1
java.io.IOException : 일부 서버에서 예기치 않은 스트림 끝 을 얻을 수 있습니다.이를 수정하려면 connection.setRequestProperty ( "Accept-Encoding", "musixmatch"); 알려진 문제이며 code.google.com
Marcin Waśniowski

1
@BalusC (200 <= responseCode) 조건이 중복됨을 의미하는 (응답 <= 399) 경우에만 (200 <= responseCode && responseCode <= 399)가 true이므로, 그래서 나는 그것이 실수라고 생각했다.
metator

4
@metator : 응 ??? 절대 중복되지 않습니다. 200 미만의 응답 코드는 유효하지 않은 것으로 간주됩니다.
BalusC

1
@BalusC 일부 상황에서는이 방법이 제대로 작동하지 않는 것 같습니다. 여기를보세요 stackoverflow.com/questions/25805580/…
AndreaF

17

URLConnection을 사용하는 대신 URL 객체에서 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();
        }
    }

비슷한 질문 을 확인하십시오 URL이 존재하는지 확인하거나 Java로 404를 반환하는 방법은 무엇입니까?

도움이 되었기를 바랍니다.



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 년 현재 하루 1,300 억 건의 요청을 처리합니다. 응답하지 않는 앱은 아마도 오늘의 이야기가 아닐 것입니다.

링크를 읽으십시오. 아주 좋아 보인다

편집 : 내 경험에 따르면이 방법만큼 빠르지 않습니다.

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.